-
Notifications
You must be signed in to change notification settings - Fork 3
/
wcc.h
1487 lines (1337 loc) · 54.5 KB
/
wcc.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
#include <stdio.h>
#include <sys/time.h>
#define MAX_CPP_FILESIZE 10 * 1024 * 1024
#define MAX_CPP_INCLUDE_DEPTH 15
#define MAX_CPP_MACRO_PARAM_COUNT 1024
#define MAX_STRUCT_OR_UNION_SCALARS 1024
#define MAX_TYPEDEFS 1024
#define MAX_STRUCT_MEMBERS 1024
#define MAX_IDENTIFIER_SIZE 1024
#define MAX_INPUT_SIZE 1 << 20 // 1 MB
#define MAX_STRING_LITERAL_SIZE 4095
#define MAX_STRING_LITERALS 20480
#define MAX_FLOATING_POINT_LITERALS 10240
#define VALUE_STACK_SIZE 10240
#define MAX_VREG_COUNT 20480
#define PHYSICAL_REGISTER_COUNT 32 // integer + xmm
#define PHYSICAL_INT_REGISTER_COUNT 12 // Available registers for integers
#define PHYSICAL_SSE_REGISTER_COUNT 14 // Available registers for floating points
#define MAX_SPILLED_REGISTER_COUNT 1024
#define MAX_INPUT_FILENAMES 1024
#define MAX_BLOCKS 10240
#define MAX_BLOCK_EDGES 1024
#define MAX_STACK_SIZE 10240
#define MAX_BLOCK_PREDECESSOR_COUNT 1024
#define MAX_GRAPH_EDGE_COUNT 10240
typedef struct block {
struct three_address_code *start, *end;
} Block;
typedef struct graph_node {
int id;
struct graph_edge *pred;
struct graph_edge *succ;
} GraphNode;
typedef struct graph_edge {
int id;
GraphNode *from;
GraphNode *to;
struct graph_edge *next_pred;
struct graph_edge *next_succ;
} GraphEdge;
typedef struct graph {
GraphNode *nodes;
GraphEdge *edges;
int node_count;
int edge_count;
int max_edge_count;
} Graph;
typedef struct set {
int max_value;
char *elements;
int cached_element_count;
int *cached_elements;
} Set;
typedef struct stack {
int *elements;
int pos;
} Stack;
typedef struct strmap {
char **keys;
void **values;
int size;
int used_count;
int element_count;
} StrMap;
typedef struct strmap_iterator {
StrMap *map;
int pos;
int original_size;
} StrMapIterator;
typedef struct strset {
StrMap *strmap;
} StrSet;
typedef struct longmap {
long *keys;
void **values;
char *status;
int size;
int used_count;
int element_count;
long (*hashfunc)(long);
} LongMap;
typedef struct longmap_iterator {
LongMap *map;
int pos;
int original_size;
} LongMapIterator;
typedef struct longset {
LongMap *longmap;
} LongSet;
typedef struct longset_iterator {
LongMapIterator longmap_iterator;
} LongSetIterator;
typedef struct circular_linked_list {
void *target;
struct circular_linked_list *next;
} CircularLinkedList;
// One of preg or stack_index must have a value. (preg != 0) != (stack_index < 0)
typedef struct vreg_location {
int preg; // Physical register starting at 0. -1 is unused.
int stack_index; // Stack index starting at -1. 0 is unused.
} VregLocation;
typedef struct vreg_i_graph {
int igraph_id;
int count;
} VregIGraph;
typedef struct i_graph_node {
struct three_address_code *tac;
struct value *value;
} IGraphNode;
typedef struct i_graph {
IGraphNode *nodes;
Graph *graph;
int node_count;
} IGraph;
enum {
SC_NONE,
SC_EXTERN,
SC_STATIC,
SC_AUTO,
SC_REGISTER,
};
typedef struct list {
int length;
int allocated;
void **elements;
} List;
typedef struct function_type {
struct scope *scope; // Scope, starting with the parameters
int param_count; // Number of parameters
List *param_types; // List of types of parameters
List *param_identifiers; // List of names of parameters
int is_variadic; // Set to 1 for builtin variadic functions
int is_paramless; // No parameters are declared, it's an old style K&R function definition
struct function_param_allocation *return_value_fpa; // function_param_allocaton for the return value if it's a struct or union
} FunctionType;
typedef struct type {
int type; // One of TYPE_*
int array_size;
unsigned int is_unsigned:1;
unsigned int is_const:1;
unsigned int is_volatile:1;
unsigned int is_restrict:1;
char storage_class;
struct type *target;
struct tag *tag; // For structs, unions and enums
struct struct_or_union_desc *struct_or_union_desc;
FunctionType *function; // For functions
} Type;
typedef struct type_iterator {
Type *type; // The top level type being iterated
int index; // The index within the type. -1 if the end has been reached
int offset; // Offset at the position of the iterator
int start_offset; // Offset when the iterator started on an array or struct/union
int bit_field_offset; // Bit field offset if the scalar is a bit field
int bit_field_size; // Bit field size if the scalar is a bit field
struct type_iterator *parent; // Parent to recurse back to
} TypeIterator;
typedef struct initializer {
int offset; // Offset of the initializer
int size; // Size of the initializer
void *data; // Pointer to the data, or zero if it's a block of zeroes
int is_string_literal; //
int string_literal_index; // If it's a string literal, an index in string_literals
int is_address_of; // When set, the initializer must also be either a string literal or have a symbol
int address_of_offset; // Offset when used in combination with is_address_of
struct symbol *symbol; // Used together with address of.
} Initializer;
typedef struct symbol {
Type *type; // Type
struct function *function; // Set if the symbol is a function
int size; // Size
char *identifier; // Identifier
char *global_identifier; // Same as identifier for globals, autogenerated for static locals, or otherwise null
struct scope* scope; // Scope
int linkage; // One of LINKAGE_*
long value; // Value in the case of a constant
int local_index; // Used by the parser for locals variables and function arguments
// < 0 is a local variable or tempoary, >= 2 is a function parameter
int is_enum_value; // Enums are symbols with a value
List *initializers; // Set when a global object is initialized;
} Symbol;
typedef struct tag {
Type *type; // Type
char *identifier; // Identifier
} Tag;
typedef struct scope {
struct scope *parent; // Parent scope, zero if it's the global scope
StrMap *symbols; // Symbols
List *symbol_list; // List of symbols, in order of declaration/definition
StrMap *tags; // Struct, union or enum tags
} Scope;
typedef struct function {
Type *type; // Type of the function
int local_symbol_count; // Number of local symbols, used by the parser
int vreg_count; // Number of virtual registers used in IR
int stack_register_count; // Amount of stack space needed for registers spills
int stack_size; // Size of the stack
int is_defined; // if a definition has been found
List *static_symbols; // Static symbols
struct value *return_value_pointer; // Set to the register holding the memory return address if the function returns something in memory
struct function_param_allocation *fpa; // function_param_allocaton for the params
struct three_address_code *ir; // Intermediate representation
StrMap *labels; // Map of identifiers to label ids
CircularLinkedList *goto_backpatches; // Gotos to labels not yet defined
struct value *register_save_area; // Place where variadic functions store the arguments in registers
Graph *cfg; // Control flow graph
Block *blocks; // For functions, the blocks
Set **dominance; // Block dominances
LongSet **uevar; // The upward exposed set for each block
LongSet **varkill; // The killed var set for each block
LongSet **liveout; // The liveout set for each block
int *idom; // Immediate dominator for each block
Set **dominance_frontiers; // Dominance frontier for each block
Set **var_blocks; // Var/block associations for vars that are written to
Set *globals; // All variables that are assigned to
Set **phi_functions; // All variables that need phi functions for each block
char *interference_graph; // The interference graph of live ranges, in a lower diagonal matrix
struct vreg_location *vreg_locations; // Allocated physical registers and spilled stack indexes
int *spill_cost; // The estimated spill cost for each live range
char *preferred_live_range_preg_indexes; // Preferred physical register, when possible
char *vreg_preg_classes; // Preg classes for all vregs
} Function;
// Data of the a single eight byte that's part of a struct or union function parameter or arg
typedef struct function_param_location {
// Details of the struct/union
int stru_offset; // Starting offset in the case of a struct/union
int stru_size; // Number of bytes in the 8-byte in the case of a struct/union
int stru_member_count; // Amount of members in the 8-byte in the case of a struct/union
// Details of where the function param/arg goes, either in a register or the stack
// One of int_register/sse_register/stack_offset is not -1.
int int_register; // If not -1, an int register
int sse_register; // If not -1, an sse register
int stack_offset; // If not -1 the stack offset
int stack_padding; // If not -1 the stack padding
} FunctionParamLocation;
typedef struct function_param_locations {
int count;
FunctionParamLocation *locations;
} FunctionParamLocations;
typedef struct function_param_allocation {
int single_int_register_arg_count;
int single_sse_register_arg_count;
int biggest_alignment;
int offset;
int padding;
int size;
List *param_locations;
} FunctionParamAllocation;
// Physical register class
enum {
PC_INT = 1,
PC_SSE = 2,
};
// Value is a value on the value stack. A value can be one of
// - global
// - local
// - constant
// - string literal
// - register
typedef struct value {
Type *type; // Type
int vreg; // Optional vreg number
int preg; // Allocated physical register
char preg_class; // Class of physical register, PC_INT or PC_SSE
unsigned int is_lvalue:1; // Is the value an lvalue?
unsigned int is_lvalue_in_register:1; // Is the value an lvalue in a register?
unsigned int spilled:1; // 1 if spilled
unsigned int is_constant:1; // Is it a constant? If so, value is the value.
unsigned int is_string_literal:1; // Is the value a string literal?
unsigned int has_been_renamed:1; // Used in renaming and stack renumbering code
unsigned int is_address_of:1; // Is an address of a constant expression.
unsigned int has_struct_or_union_return_value:1; // Is it a function call that returns a struct/union?
unsigned int load_from_got:1; // Load from Global Offset Table (GOT)
int local_index; // Used by parser for local variable and temporaries and function arguments
int stack_index; // stack index in case of a pushed function argument, & usage or register spill
// < 0 is for locals, temporaries and spills. >= 2 is for pushed arguments, that start at 2.
int stack_offset; // Position on the stack
int string_literal_index; // Index in the string_literals array in the case of a string literal
long int_value; // Value in the case of an integer constant
long double fp_value; // Value in the case of a floating point constant
int offset; // For composite objects, offset from the start of the object's memory
int bit_field_offset; // Offset in bits for bit fields
int bit_field_size; // Size in bits for bit fields
int is_overflow_arg_area_address; // Set to indicate this value must point to the saved register save overflow for variadic functions
Symbol *function_symbol; // Corresponding symbol in the case of a function call
int address_of_offset; // Offset when used in combination with is_address_of
int live_range_preg; // This value is bound to a physical register
int function_param_original_stack_index; // Original stack index for function parameter pushed onto the stack
int function_call_arg_index; // Index of the argument (0=leftmost)
FunctionParamLocations *function_call_arg_locations; // Destination of the arg, either a single int or sse register, or in the case of a struct, a list of locations
int function_call_sse_register_arg_index; // Index of the argument in integer registers going left to right (0=leftmost). Set to -1 if it's on the stack.
int function_call_arg_stack_padding; // Extra initial padding needed to align the function call argument pushed arguments
int function_call_arg_push_count; // Number of arguments pushed on the stack
int function_call_sse_register_arg_count; // Number of SSE (xmm) arguments in registers
Set *return_value_live_ranges; // Live ranges for registers that are part of the function return values
Symbol *global_symbol; // Pointer to a global symbol if the value is a global symbol
int label; // Target label in the case of jump instructions
int ssa_subscript; // Optional SSA enumeration
int live_range; // Optional SSA live range
char preferred_live_range_preg_index; // Preferred physical register
int x86_size; // Current size while generating x86 code
int non_terminal; // Used in rule matching
} Value;
typedef struct origin {
char *filename;
int line_number;
} Origin;
typedef struct three_address_code {
int index; // Index in a tac chain
int operation; // IR_* operation
int label; // Label if this instruction is jumped to
Value *dst; // Destination
Value *src1; // First rhs operand
Value *src2; // Second rhs operand
Value *phi_values; // For phi functions, a null terminated array of values for the args
struct three_address_code *next; // Next in a linked-list
struct three_address_code *prev; // Previous in a linked-list
char *x86_template; // Template for rendering x86 instruction
Origin *origin; // Filename and line numberwhere the tac was created
} Tac;
// Struct/union member
typedef struct struct_or_union_member {
char *identifier;
Type *type;
int offset;
int is_bit_field;
int bit_field_size;
int bit_field_offset;
} StructOrUnionMember;
// Struct & union description
typedef struct struct_or_union_desc {
int size;
int is_incomplete; // Set to 1 if the struct has been used in a member but not yet declared
int is_packed;
int is_union;
struct struct_or_union_member **members;
} StructOrUnion;
typedef struct typedef_desc {
char *identifier;
Type *type;
} Typedef;
typedef struct register_set {
int *int_registers;
int *sse_registers;
} RegisterSet;
// Tokens in order of precedence
enum {
TOK_EOF=1,
TOK_IDENTIFIER,
TOK_INTEGER,
TOK_FLOATING_POINT_NUMBER,
TOK_STRING_LITERAL,
TOK_IF,
TOK_ELSE,
TOK_SIGNED,
TOK_UNSIGNED,
TOK_INLINE, // 10
TOK_VOID,
TOK_CHAR,
TOK_INT,
TOK_SHORT,
TOK_LONG,
TOK_FLOAT,
TOK_DOUBLE,
TOK_STRUCT,
TOK_UNION,
TOK_TYPEDEF, // 20
TOK_TYPEDEF_TYPE,
TOK_DO,
TOK_WHILE,
TOK_FOR,
TOK_SWITCH,
TOK_CASE,
TOK_DEFAULT,
TOK_CONTINUE,
TOK_BREAK,
TOK_RETURN, // 30
TOK_ENUM,
TOK_SIZEOF,
TOK_RCURLY,
TOK_LCURLY,
TOK_SEMI,
TOK_COMMA,
TOK_EQ,
TOK_PLUS_EQ,
TOK_MINUS_EQ,
TOK_MULTIPLY_EQ, // 40
TOK_DIVIDE_EQ,
TOK_MOD_EQ,
TOK_BITWISE_AND_EQ,
TOK_BITWISE_OR_EQ,
TOK_BITWISE_XOR_EQ,
TOK_BITWISE_RIGHT_EQ,
TOK_BITWISE_LEFT_EQ,
TOK_TERNARY,
TOK_COLON,
TOK_OR, // 50
TOK_AND,
TOK_BITWISE_OR,
TOK_XOR,
TOK_AMPERSAND,
TOK_DBL_EQ,
TOK_NOT_EQ,
TOK_LT,
TOK_GT,
TOK_LE,
TOK_GE, // 60
TOK_BITWISE_LEFT,
TOK_BITWISE_RIGHT,
TOK_PLUS,
TOK_MINUS,
TOK_MULTIPLY,
TOK_DIVIDE,
TOK_MOD,
TOK_LOGICAL_NOT,
TOK_BITWISE_NOT,
TOK_INC, // 70
TOK_DEC,
TOK_DOT,
TOK_ARROW,
TOK_RBRACKET,
TOK_LBRACKET,
TOK_RPAREN,
TOK_LPAREN,
TOK_ATTRIBUTE,
TOK_PACKED,
TOK_ALIGNED, // 80
TOK_HASH,
TOK_AUTO,
TOK_REGISTER,
TOK_STATIC,
TOK_EXTERN,
TOK_CONST,
TOK_VOLATILE,
TOK_RESTRICT,
TOK_ELLIPSES,
TOK_GOTO, // 90
TOK_ASM,
};
enum {
TYPE_VOID = 1,
TYPE_CHAR = 2,
TYPE_SHORT = 3,
TYPE_INT = 4,
TYPE_LONG = 5,
TYPE_FLOAT = 6,
TYPE_DOUBLE = 7,
TYPE_LONG_DOUBLE = 8,
TYPE_PTR = 9,
TYPE_ARRAY = 10,
TYPE_STRUCT_OR_UNION = 11,
TYPE_ENUM = 12,
TYPE_FUNCTION = 13,
TYPE_TYPEDEF = 14
};
enum {
LINKAGE_NONE = 1,
LINKAGE_INTERNAL,
LINKAGE_IMPLICIT_EXTERNAL,
// Used for a) static local symbols that need to be global, but with internal
// linkage and b) global symbols with extern symbol This mimicks what gcc does.
// LINKAGE_UNDECLARED_EXTERNAL is equivalent to LINKAGE_IMPLICIT_EXTERNAL in codegen, the
// difference is only used when reporting errors in the parser.
LINKAGE_EXPLICIT_EXTERNAL,
};
// Intermediate representation operations
enum {
IR_MOVE=1, // Moving of constants, string literals, variables, or registers
IR_MOVE_TO_PTR, // Assignment to a pointer target
IR_MOVE_PREG_CLASS, // Move int <-> sse without conversion
IR_MOVE_STACK_PTR, // Move RSP -> register
IR_ADDRESS_OF, // &
IR_INDIRECT, // Pointer or lvalue dereference
IR_DECL_LOCAL_COMP_OBJ, // Declare a local compound object
IR_LOAD_BIT_FIELD, // Load a bit field into a register
IR_SAVE_BIT_FIELD, // Save a bit field into a register
IR_LOAD_FROM_GOT, // Load object from global offset table (for PIC)
IR_ADDRESS_OF_FROM_GOT, // & an object from global offset table (for PIC)
IR_START_CALL, // Function call
IR_ARG, // Function call argument
IR_ARG_STACK_PADDING, // Extra padding push to align arguments pushed onto the stack
IR_CALL_ARG_REG, // Placeholder for fake read/write of a physical register to keep a live range alive
IR_CALL, // Start of function call
IR_END_CALL, // End of function call
IR_VA_START, // va_start function call
IR_VA_ARG, // va_arg function call
IR_ALLOCATE_STACK, // Allocate stack space for a function call argument on the stack
IR_RETURN, // Return in function
IR_ZERO, // Zero a block of memory
IR_LOAD_LONG_DOUBLE, // Load a long double into the top of the x87 stack
IR_START_LOOP, // Start of a for or while loop
IR_END_LOOP, // End of a for or while loop
IR_NOP, // No operation. Used for label destinations. No code is generated for this other than the label itself.
IR_JMP, // Unconditional jump
IR_JZ, // Jump if zero
IR_JNZ, // Jump if not zero
IR_ADD, // +
IR_SUB, // -
IR_RSUB, // reverse -, used to facilitate code generation for the x86 SUB instruction
IR_MUL, // *
IR_DIV, // /
IR_MOD, // %
IR_EQ, // ==
IR_NE, // !=
IR_LOR, // Logical or |
IR_LAND, // Logical and &
IR_LNOT, // Logical not
IR_BNOT, // Binary not ~
IR_BOR, // Binary or |
IR_BAND, // Binary and &
IR_XOR, // Binary xor ^
IR_BSHL, // Binary shift left <<
IR_BSHR, // Binary shift right >>
IR_ASHR, // Arithmetic shift right >>
IR_LT, // <
IR_GT, // >
IR_LE, // <=
IR_GE, // >=
IR_PHI_FUNCTION, // SSA phi function
};
// Physical registers
enum {
// Integers
REG_RAX,
REG_RBX,
REG_RCX,
REG_RDX,
REG_RSI,
REG_RDI,
REG_RBP,
REG_RSP,
REG_R08,
REG_R09,
REG_R10,
REG_R11,
REG_R12,
REG_R13,
REG_R14,
REG_R15,
// SSE
REG_XMM00,
REG_XMM14 = 30,
REG_XMM15,
};
enum {
OVERFLOW_AREA_ADDRESS_MAGIC_STACK_INDEX = 256
};
typedef struct string_literal {
char *data;
int size;
int is_wide_char;
} StringLiteral;
enum {
CPP_TOK_EOL=1,
CPP_TOK_EOF,
CPP_TOK_IDENTIFIER,
CPP_TOK_STRING_LITERAL,
CPP_TOK_HCHAR_STRING_LITERAL,
CPP_TOK_NUMBER,
CPP_TOK_HASH,
CPP_TOK_PASTE,
CPP_TOK_INCLUDE,
CPP_TOK_DEFINE,
CPP_TOK_UNDEF,
CPP_TOK_IF,
CPP_TOK_IFDEF,
CPP_TOK_IFNDEF,
CPP_TOK_ELIF,
CPP_TOK_ELSE,
CPP_TOK_ENDIF,
CPP_TOK_LINE,
CPP_TOK_DEFINED,
CPP_TOK_WARNING,
CPP_TOK_ERROR,
CPP_TOK_PRAGMA,
CPP_TOK_LPAREN,
CPP_TOK_RPAREN,
CPP_TOK_COMMA,
CPP_TOK_INC,
CPP_TOK_DEC,
CPP_TOK_OTHER,
};
typedef struct cpp_token {
int kind; // One of CPP_TOK*
char *whitespace; // Preceding whitespace
char *str; // The token text
int line_number;
int line_number_offset; // Amended line number due to #line
StrSet *hide_set; // Hide set, when expanding macros
struct cpp_token *next;
} CppToken;
typedef CppToken *(*DirectiveRenderer)(CppToken *);
typedef struct directive {
char is_function; // Is the macro an object or function macro
int param_count; // Amount of parameters.
StrMap *param_identifiers; // Mapping of parameter identifiers => index, index starts at 1
CppToken *tokens; // Replacement tokens
DirectiveRenderer renderer; // Renderer for builtin directives
} Directive;
// Structure with all directives passed on the command line with -D
typedef struct cli_directive {
char *identifier; // Identifier of the directive
Directive *directive; // The actual directive
struct cli_directive *next;
} CliDirective;
// Structure with all include paths passed on the command line with -I
typedef struct cli_include_path {
char *path;
struct cli_include_path *next;
} CliIncludePath;
// Structure with all include paths passed on the command line with -L
typedef struct cli_library_path {
char *path;
struct cli_library_path *next;
} CliLibraryPath;
// Structure with all include libraries passed on the command line with -l
typedef struct cli_library {
char *library;
struct cli_library *next;
} CliLibrary;
typedef enum {
CP_PREPROCESSING,
CP_PARSING,
CP_POST_PARSING,
} CompilePhase;
char *cur_filename; // Current filename being lexed
int cur_line; // Current line number being lexed
int print_ir1; // Print IR after parsing
int print_ir2; // Print IR after register allocation
int log_compiler_phase_durations; // Output logs of how long each compiler phase lasts
int opt_PIC; // Make position independent code
int opt_debug_symbols; // Add debug symbols
int opt_enable_vreg_renumbering; // Renumber vregs so the numbers are consecutive
int opt_enable_register_coalescing; // Merge registers that can be reused within the same operation
int opt_enable_live_range_coalescing; // Merge live ranges where possible
int opt_spill_furthest_liveness_end; // Prioritize spilling physical registers with furthest liveness end
int opt_short_lr_infinite_spill_costs; // Don't spill short live ranges
int opt_optimize_arithmetic_operations; // Optimize arithmetic operations
int opt_enable_preferred_pregs; // Enable preferred preg selection in register allocator
int opt_enable_trigraphs; // Enable trigraph preprocessing
int opt_warnings_are_errors; // Treat all warnings as errors
CliDirective *cli_directives; // Linked list of directives passed on the command line with -D
CliIncludePath *cli_include_paths; // Linked list of include paths passed on the command line with -I
CliLibraryPath *cli_library_paths; // Linked list of library paths passed on the command line with -L
CliLibrary *cli_libraries; // Linked list of libraries passed on the command line with -l
StrMap *directives; // Map of CPP directives
CompilePhase compile_phase; // One of CP_*
int cur_token; // Current token
char *cur_identifier; // Current identifier if the token is an identifier
char *cur_type_identifier; // Identifier of the last parsed declarator
Type *cur_lexer_type; // A type determined by the lexer
long cur_long; // Current long if the token is an integral type
long double cur_long_double; // Current long double if the token is a floating point type
StringLiteral cur_string_literal; // Current string literal if the token is a string literal
Scope *cur_scope; // Current scope.
StringLiteral *string_literals; // Each string literal has an index in this array, with a pointer to the string literal struct
int string_literal_count; // Amount of string literals
Symbol *cur_function_symbol; // Currently parsed function
Value *cur_loop_continue_dst; // Target jmp of continue statement in the current for/while loop
Value *cur_loop_break_dst; // Target jmp of break statement in the current for/while loop
Typedef **all_typedefs; // All typedefs
int all_typedefs_count; // Number of typedefs
Tac *ir_start, *ir; // intermediate representation for currently parsed function
int label_count; // Global label count, always growing
int cur_loop; // Current loop being parsed
int loop_count; // Loop counter
int stack_register_count; // Spilled register count for current function that's undergoing register allocation
int total_stack_register_count; // Spilled register count for all functions
int cur_stack_push_count; // Used in codegen to keep track of stack position
int callee_saved_registers[PHYSICAL_REGISTER_COUNT + 1]; // Set to 1 for registers that must be preserved in function calls.
int int_arg_registers[6];
int sse_arg_registers[8];
FILE *f; // Output file handle
int warn_integer_constant_too_large;
int warn_assignment_types_incompatible;
int debug_function_param_allocation;
int debug_function_arg_mapping;
int debug_function_param_mapping;
int debug_ssa_mapping_local_stack_indexes;
int debug_ssa;
int debug_ssa_liveout;
int debug_ssa_cfg;
int debug_ssa_dominance;
int debug_ssa_idom;
int debug_ssa_dominance_frontiers;
int debug_ssa_phi_insertion;
int debug_ssa_phi_renumbering;
int debug_ssa_live_range;
int debug_ssa_vreg_renumbering;
int debug_ssa_interference_graph;
int debug_ssa_live_range_coalescing;
int debug_ssa_spill_cost;
int debug_register_allocation;
int debug_graph_coloring;
int debug_instsel_tree_merging;
int debug_instsel_tree_merging_deep;
int debug_instsel_igraph_simplification;
int debug_instsel_tiling;
int debug_instsel_cost_graph;
int debug_instsel_spilling;
int debug_stack_frame_layout;
int debug_exit_after_parser;
int debug_dont_compile_internals;
#define free_and_null(object) do { wfree(object); object = NULL; } while(0);
// set.c
#define add_to_set(s, value) do { \
if (value > s->max_value) panic("Max set value of %d exceeded with %d in add_to_set", s->max_value, value); \
s->elements[value] = 1; \
} while (0)
Set *new_set(int max_value);
void free_set(Set *s);
void empty_set(Set *s);
Set *copy_set(Set *s);
void copy_set_to(Set *dst, Set *src);
void cache_set_elements(Set *s);
int set_len(Set *s);
void print_set(Set *s);
int in_set(Set *s, int value);
int set_eq(Set *s1, Set *s2);
void *delete_from_set(Set *s, int value);
Set *set_intersection(Set *s1, Set *s2);
void set_intersection_to(Set *dst, Set *s1, Set *s2);
Set *set_union(Set *s1, Set *s2);
void set_union_to(Set *dst, Set *s1, Set *s2);
Set *set_difference(Set *s1, Set *s2);
void set_difference_to(Set *dst, Set *s1, Set *s2);
// stack.c
Stack *new_stack(void);
void free_stack(Stack *s);
int stack_top(Stack *s);
void push_onto_stack(Stack *s, int v);
int pop_from_stack(Stack *s);
// strmap.c
StrMap *new_strmap(void);
void free_strmap(StrMap *map);
void *strmap_get(StrMap *strmap, char *key);
void strmap_put(StrMap *strmap, char *key, void *value);
void strmap_delete(StrMap *strmap, char *key);
StrMapIterator strmap_iterator(StrMap *map);
int strmap_iterator_finished(StrMapIterator *iterator);
void strmap_iterator_next(StrMapIterator *iterator);
char *strmap_iterator_key(StrMapIterator *iterator);
#define strmap_foreach(ls, it) for (StrMapIterator it = strmap_iterator(ls); !strmap_iterator_finished(&it); strmap_iterator_next(&it))
// strset.c
StrSet *new_strset(void);
void free_strset(StrSet *ss);
void strset_add(StrSet *ss, char *element);
int strset_in(StrSet *ss, char *element);
StrSet *dup_strset(StrSet *ss);
StrSet *strset_union(StrSet *ss1, StrSet *ss2);
StrSet *strset_intersection(StrSet *ss1, StrSet *ss2);
void print_strset(StrSet *s);
// longset.c
LongSet *new_longset(void);
void free_longset(LongSet *ss);
void longset_add(LongSet *ss, long element);
void longset_delete(LongSet *ls, long element);
int longset_in(LongSet *ss, long element);
void longset_empty(LongSet *ls);
LongSet *longset_copy(LongSet *ls);
int longset_eq(LongSet *ss1, LongSet *ss2);
int longset_len(LongSet *ls);
LongSet *longset_union(LongSet *ss1, LongSet *ss2);
LongSet *longset_intersection(LongSet *ss1, LongSet *ss2);
#define longset_iterator_finished(iterator) longmap_iterator_finished(&(iterator)->longmap_iterator)
void longset_iterator_next(LongSetIterator *iterator);
#define longset_iterator_element(iterator) longmap_iterator_key(&(iterator)->longmap_iterator)
LongSetIterator longset_iterator(LongSet *ls);
void print_longset(LongSet *s);
#define longset_foreach(ls, it) for (LongSetIterator it = longset_iterator(ls); !longset_iterator_finished(&it); longset_iterator_next(&it))
// longmap.c
LongMap *new_longmap(void);
void free_longmap(LongMap *map);
void *longmap_get(LongMap *longmap, long key);
void longmap_put(LongMap *longmap, long key, void *value);
void longmap_delete(LongMap *longmap, long key);
int longmap_keys(LongMap *map, int **keys);
void longmap_empty(LongMap *map);
LongMap *longmap_copy(LongMap *map);
LongMapIterator longmap_iterator(LongMap *map);
#define longmap_iterator_finished(iterator) ((iterator)->pos == -1)
void longmap_iterator_next(LongMapIterator *iterator);
#define longmap_iterator_key(iterator) (iterator)->map->keys[(iterator)->pos]
#define longmap_foreach(map, it) for (LongMapIterator it = longmap_iterator(map); !longmap_iterator_finished(&it); longmap_iterator_next(&it))
// list.c
// Append to circular linked list of allocated tokens
#define append_to_cll(cll, new_target) \
do { \
if (cll) { \
CircularLinkedList *next = wmalloc(sizeof(CircularLinkedList)); \
next->target = new_target; \
next->next = cll->next; \
cll->next = next; \
cll = next; \
} \
else { \
cll = wmalloc(sizeof(CircularLinkedList)); \
cll->target = new_target; \
cll->next = cll; \
} \
} while(0)
void free_circular_linked_list(CircularLinkedList *cll);
List *new_list(int length);
void free_list(List *l);
void append_to_list(List *l, void *element);
// graph.c
Graph *new_graph(int node_count, int edge_count);
void free_graph(Graph *g);
void dump_graph(Graph *g);
GraphEdge *add_graph_edge(Graph *g, int from, int to);
// utils.c
// A struct for appending strings to a buffer without knowing the size beforehand
typedef struct string_buffer {
char *data;
int position;
int allocated;
} StringBuffer;
void panic(char *format, ...);
char *base_path(char *path);
int wasprintf(char **ret, const char *format, ...);
StringBuffer *new_string_buffer(int initial_size);
void free_string_buffer(StringBuffer *sb, int free_data);
void append_to_string_buffer(StringBuffer *sb, char *str);
void terminate_string_buffer(StringBuffer *sb);
int set_debug_logging_start_time();
int debug_log(char *format, ...);
// memory.c
int print_heap_usage;
int fail_on_leaked_memory;
void *wmalloc(size_t size);
void *wrealloc(void *ptr, size_t size);
void *wcalloc(size_t nitems, size_t size);
void *wcalloc(size_t nitems, size_t size);
char *wstrdup(const char *str);
void wfree(void *ptr);
void process_memory_allocation_stats(void);
// error.c
void panic_with_line_number(char *format, ...);
void simple_error(char *format, ...);
void error(char *format, ...);
void warning(char *format, ...);
// lexer.c
void init_lexer_from_filename(char *filename);
void init_lexer_from_string(char *string);
void free_lexer(void);
void next(void);
void rewind_lexer(void);
void expect(int token, char *what);
void consume(int token, char *what);
// cpp.c
typedef struct line_map {
int position;
int line_number;
struct line_map *next;
} LineMap;
void init_cpp(void);
void get_cpp_filename_and_line();
void init_cpp_from_string(char *string);
char *get_cpp_input(void);
void init_directives(void);
void free_directives(void);
LineMap *get_cpp_linemap(void);
void transform_trigraphs(void);
void strip_backslash_newlines(void);
Directive *parse_cli_define(char *string);
char *preprocess(char *filename, List *cli_directive_strings);
void preprocess_to_file(char *input_filename, char *output_filename, List *cli_directive_strings);
void free_cpp_allocated_garbage();
// parser.c
typedef Value *parse_expression_function_type(int);
Value *make_string_literal_value_from_cur_string_literal(void);
Value *new_label_dst(void);
Symbol *memcpy_symbol;
Symbol *memset_symbol;
int cur_token_is_type(void);
Type *operation_type(Value *src1, Value *src2, int for_ternary);
void check_unary_operation_type(int operation, Value *value);
void check_binary_operation_types(int operation, Value *src1, Value *src2);
void check_plus_operation_type(Value *src1, Value *src2, int for_array_subscript);
void check_minus_operation_type(Value *src1, Value *src2);
void check_ternary_operation_types(Value *switcher, Value *src1, Value *src2);
Value *load_constant(Value *cv);
Type *parse_type_name(void);
void parse_typedef(void);
Type *find_struct_or_union(char *identifier, int is_union, int recurse);
StructOrUnionMember *lookup_struct_or_union_member(Type *type, char *identifier);
Value *make_symbol_value(Symbol *symbol);
int parse_sizeof(parse_expression_function_type expr);
void parse(void);
void dump_symbols(void);
void init_parser(void);
void free_parser(void);
// constexpr.c
Value* evaluate_const_unary_int_operation(int operation, Value *value);
Value* evaluate_const_binary_int_operation(int operation, Value *src1, Value *src2);
Value* evaluate_const_binary_fp_operation(int operation, Value *src1, Value *src2, Type *type);
Value *cast_constant_value(Value *src, Type *type);
Value *parse_constant_expression(int level);
Value *parse_constant_integer_expression(int all_longs);
// scopes.c
Scope *global_scope;
void init_scopes(void);
void free_scopes(void);
void enter_scope(void);