forked from davidgiven/ack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcg.doc
1848 lines (1822 loc) · 56 KB
/
cg.doc
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
.RP
.ND Nov 1984
.TL
The table driven code generator from
.br
the Amsterdam Compiler Kit
.AU
Hans van Staveren
.AI
Dept. of Mathematics and Computer Science
Vrije Universiteit
Amsterdam, The Netherlands
.AB
It is possible to automate the process of compiler building
to a great extent using collections of tools.
The Amsterdam Compiler Kit is such a collection of tools.
This document provides a description of the internal workings
of the table driven code generator in the Amsterdam Compiler Kit,
and a description of syntax and semantics of the driving table.
.PP
>>> NOTE <<<
.br
This document pertains to the \fBold\fP code generator. Refer to the
"Second Revised Edition" for the new code generator.
.AE
.NH 1
Introduction
.PP
Part of the Amsterdam Compiler Kit is a code generator system consisting
of a code generator generator (\fIcgg\fP for short) and some machine
independent C code.
.I Cgg
reads a machine description table and creates two files,
tables.h and tables.c.
These are then used together with other C code to produce
a code generator for the machine at hand.
.PP
This in turn reads compact EM code and produces
assembly code.
The remainder of this document will first broadly describe
the working of the code generator,
then a description of the machine table follows after which
the internal workings of the code generator will be explained.
.PP
The reader is assumed to have at least a vague notion about the
semantics of the intermediary EM code.
Someone wishing to write a table for a new machine
should be thoroughly acquainted with EM code
and the assembly code of the machine at hand.
.NH 1
Global overview of the workings of the code generator.
.PP
The code generator or
.I cg
tries to generate good code by simulating the runtime stack
of the program compiled and delaying emission of code as long
as possible.
It also keeps track of register contents, which enables it to
eliminate redundant moves, and tries to eliminate redundant tests
by keeping information about condition code status,
if applicable for the machine.
.PP
.I Cg
maintains a `fakestack' containing `tokens' that are built
by executing the pseudo code contained in the code rules given
by the table writer.
One can think of the fakestack as a logical extension of the real
stack the program compiled will have when run.
During code generation tokens will be kept on the fakestack as long
as possible but when they are moved to the real stack,
by generating code for the push,
all tokens above\u*\d
.FS
* in the rest of this document the stack is assumed to grow downwards,
although the top of the stack will mean the first element that will
be popped.
.FE
the tokens pushed will be pushed also,
so that the fakestack will not contain holes.
.PP
The main loop of
.I cg
is this:
.IP 1)
find a pattern of EM instructions starting at the current one to
generate code for.
This pattern will usually be of length one but longer patterns can be used.
.IP 2)
Select one of the possibly many stack patterns that go with this
EM pattern on the basis of heuristics and/or lookahead.
.IP 3)
Force the current fakestack contents to match the pattern.
This may involve
copying tokens to registers, making dummy transformations, e.g. to
transform a "local" into an "register offsetted" or might even
cause to have the complete fakestack contents put to the real stack
and then back into registers if no suitable transformations
were provided by the table writer.
.IP 4)
Execute the pseudocode associated with the code rule just selected,
this may cause registers to be allocated,
code to be emitted etc..
.IP 5)
Put tokens onto the fakestack to reflect the result of the operation.
.IP 6)
Insert some EM instructions into the stream,
this is possible but not common.
.IP 7)
Account for the cost.
The cost is kept in a (space, time) vector and lookahead decisions
are based on a linear combination of these.
.PP
The table that drives
.I cg
is not read in every time,
but instead is used at compiletime
of
.I cg
to set parameters and to load pseudocode tables.
A program called
.I cgg
reads the table and produces large lists of numbers that are
compiled together with machine independent code to produce
a code generator for the machine at hand.
.NH 1
Description of the machine table
.PP
The machine description table consists of the following sections:
.IP 1)
Constant definitions
.IP 2)
Register definitions
.IP 3)
Token definitions
.IP 4)
Token expression definitions
.IP 5)
Code rules
.IP 6)
Move definitions
.IP 7)
Test definitions
.IP 8)
Stacking definitions
.PP
Input is in free format, white space and newlines may be used
at will to improve legibility.
Identifiers used in the table have the same syntax as C identifiers,
upper and lower case considered different, all characters significant.
There is however one exception:
identifiers must be more than one character long for parsing reasons.
C style comments are accepted
.DS
/* this is a comment */
.DE
and #define macros may be used if the need arises.
.NH 2
Some constants
.PP
Before anything else three constants must be defined,
all with the syntax NAME=value, value being an integer.
These constants are:
.IP EM_WSIZE 10
Number of bytes in a machine word.
This is the number of bytes
a simple \fBloc\fP instruction will put on the stack.
.IP EM_PSIZE
Number of bytes in a pointer.
This is the number of bytes
a \fBlal\fP instruction will put on the stack.
.IP EM_BSIZE
Number of bytes in the hole between AB and LB.
If the calling sequence just saves PC and LB this
size will be twice the pointersize.
.PP
EM_WSIZE and EM_PSIZE are checked when a program is compiled
with the resulting code generator.
EM_BSIZE is used by
.I cg
to add to the offset of instructions dealing with locals
having positive offsets,
i.e. parameters.
.PP
Optionally one can give here the factors with which the size and time
parts of the cost function have to be multiplied to ensure they have the
same order of magnitude.
This can be done as
.DS
TIMEFACTOR = C\d1\u/C\d2\u
SIZEFACTOR = C\d3\u/C\d4\u
.DE
Above numbers must be read as rational numbers.
Defaults are 1/1 for both of them.
These constants set the default size/time tradeoff in the code generator,
so if TIMEFACTOR and SIZEFACTOR are both 1 the code generator will choose
at random between two codesequences where one has
cost (10,4) and the other has cost (8,6).
See also the description of the cost field below.
.PP
Also optional is the definition of a printformat for integers in the codefile.
This is given as
.DS
FORMAT = string
.DE
The default for string is "%ld".
For example on the PDP 11 one can use
.DS
FORMAT= "0%lo"
.DE
to satisfy the old UNIX assembler that reads octal unless followed by
a period, and the ACK assembler that follows C conventions.
.NH 2
Register definition
.PP
The next part of the tables describes the various registers of the
machine and defines identifiers
to be used in later parts of the tables.
Example for the PDP-11:
.DS L
REGISTERS:
R0 = ( "r0",2), REG.
R1 = ( "r1",2), REG, ODDREG.
R2 = ( "r2",2), REG.
R3 = ( "r3",2), REG, ODDREG.
R4 = ( "r4",2), REG.
LB = ( "r5",2), LOCALBASE.
R01= ( "r0",4,R0,R1), REGPAIR.
R23= ( "r2",4,R2,R3), REGPAIR.
FR0= ( "r0",4), FREG.
FR1= ( "r1",4), FREG.
FR2= ( "r2",4), FREG.
FR3= ( "r3",4), FREG.
DR0= ( "r0",8,FR0), DREG.
DR1= ( "r1",8,FR1), DREG.
DR2= ( "r2",8,FR2), DREG.
DR3= ( "r3",8,FR3), DREG.
.DE
.PP
The identifier before the '=' sign is the name of the register
as used further on in the table.
The string is the name of the register as far as the assembler is concerned.
The number is the size of the register in bytes.
Identifiers following the number but within the parentheses are previously
defined registernames that are contained in the register being defined.
The identifiers following the closing parenthesis are properties
of the register.
So for example R23 is a register with assembler name r2, 4 bytes long,
contains the registers R2 and R3 and has the property REGPAIR.
.PP
It might seem wise to list each and every property of a register,
so one might give R0 the extra property MFPTREG named after the not
too well known MFPT instruction on newer PDP-11 types,
but this is not a good idea.
Every extra property means the registerset is more unorthogonal
and
.I cg
execution time is influenced by that,
because it has to take into account a larger set of registers
that are not equivalent.
.PP
There is a predefined property SCRATCH that is dynamic,
i.e. a register can have the property SCRATCH one time,
and loose it the next.
A register has the property SCRATCH when it has a reference count of one.
One needs to be able to discriminate between SCRATCH registers
and others,
because it is only allowed to do arithmetic on
SCRATCH registers.
.NH 2
Stack token definition
.PP
The next part describes all possible tokens that can reside on
the fakestack during code generation.
Attributes of a token are described in the form of a C struct declaration,
this is followed by the size in bytes of the token,
optionally followed by the cost of the token when used as an addressing mode
and the format
to be used on output.
.PP
Tokens should usually be declared for every addressing mode
of the machine at hand and for every size directly usable in
a machine instruction.
Example for the PDP-11 (incomplete):
.DS L
TOKENS:
IREG2 = { REGISTER reg; } 2 "*%[reg]" /* indirect register */
REGCONST = { REGISTER reg; STRING off; } 2 /* not really addressable */
REGOFF2 = { REGISTER reg; STRING off; } 2 "%[off](%[reg])"
IREGOFF2 = { REGISTER reg; STRING off; } 2 "*%[off](%[reg])"
CONST = { INT off; } 2 cost=(2,850) "$%[off]."
EXTERN2 = { STRING off; } 2 "%[off]"
IEXTERN2 = { STRING off; } 2 "*%[off]"
PAIRSIGNED = { REGISTER regeven,regodd; } 2 "%[regeven]"
.DE
.PP
Types allowed in the struct are REGISTER, INT and STRING.
Tokens without a printformat should never be output.
.PP
Notice that tokens need not correspond to addressing modes,
the REGCONST token listed above,
meaning the sum of the contents of the register and the constant,
has no corresponding addressing mode on the PDP-11,
but is included so that a sequence of add constant, load indirect,
can be handled efficiently.
This REGCONST token is needed as part of the path
.DS
REGISTER -> REGCONST -> REGOFF
.DE
of which the first and the last "exist" and the middle is needed
only as an intermediate step.
.NH 2
Token expressions
.PP
Usually machines have certain collections of addressing modes that
can be used with certain instructions.
The stack patterns in the table are lists of these collections
and since it is cumbersome to write out these long lists
every time, there is a section here to give names to these
collections.
Please note that it is not forbidden to write out a token expression
in the remainder of the table,
but for clarity it is usually better not to.
Example for the PDP-11 (incomplete):
.DS L
TOKENEXPRESSIONS:
SOURCE2 = REG + IREG2 + REGOFF2 + IREGOFF2 + CONST + EXTERN2 +
IEXTERN2
SREG = REG * SCRATCH
.DE
Permissible in the expressions are all PASCAL set operators, i.e.
.IP +
set union
.IP -
set difference
.IP *
set intersection
.PP
Every tokenidentifier is also a token expression identifier
denoting the singleton collection of tokens containing
just itself.
Every register property as defined above is also a token expression
matching all registers with that property when on the fakestack.
The standard token expression identifier ALL denotes the collection of
all tokens.
.NH 2
Expressions
.PP
Throughout the rest of the table expressions can be used in some
places.
This section will give the syntax and semantics of expressions.
There are four types of expressions: integer, string, register and undefined.
Type checking is performed by
.I cgg .
An operator with at least one undefined operand returns undefined except
for the defined() function mentioned below.
An undefined expression is interpreted as FALSE when it is needed
as a truth value.
Basic terms in an expression are
.IP number 16
A number is a constant of type integer.
.IP "string"
A string within double quotes is a constant of type string.
All the normal C style escapes may be used within the string.
.IP REGIDENT
The name of a register is a constant of type register.
.IP $\fIi\fP
A dollarsign followed by a number is the representation of the argument
of EM instruction \fI\fP.
The type of the operand is dependent on the instruction,
sometimes it is integer,
sometimes it is string.
It is undefined when the instruction has no operand.
.br
Although an exhaustive list could be given describing all the types
the following rule of thumb will suffice.
If it is unimaginable for the operand of the instruction ever to be
something different from a plain integer, the type is integer,
otherwise it is string.
.br
.I Cg
makes all necessary conversions,
like adding EM_BSIZE to positive arguments of instructions
dealing with locals,
prepending underlines to global names,
converting codelabels into a unique representation etc.
Details about this can be found in the section about
machine dependent C code.
.IP %[1]
This in general means the token mentioned first in the
stack pattern.
When used inside an expression the token must be a simple register.
Type of this is register.
.IP %[1.off]
This means field "off" of the first stack pattern token.
Type is the same as that of field "off".
To use this expression implies a check that all tokens
in the token expression used have the same attributes.
.IP %[1.1]
This is the first subregister of the first token.
Previous comments apply.
.IP %[b]
The second allocated register.
.IP %[a.2]
The second subregister of the first allocated register.
.PP
All normal C operators apply to integers,
the + operator serves for string concatenation
and register expressions can only be compared to each other.
Furthermore there are some special "functions":
.IP tostring(e) 16
Converts an integer expression e to a string.
.IP defined(e)
Returns 1 if expression e is defined, 0 otherwise.
.IP samesign(e1,e2)
Returns 1 if integer expression e1 and e2 have the same sign.
.IP sfit(e1,e2)
Returns 1 if integer expression e1 fits as a signed integer
into a field of e2 bits, 0 otherwise.
.IP ufit(e1,e2)
Same as above but now for unsigned e1.
.IP rom(a,n)
Integer expression giving the n'th argument from the \fBrom\fP descriptor
pointed at by the a'th EM instruction.
Undefined if that descriptor does not exist.
.IP loww(a)
Returns the lower half of the argument of the a'th EM instruction.
This is used to split the arguments of a \fBldc\fP instruction.
.IP highw(a)
Same for upper half.
.NH 2
Code rules
.PP
The largest section of the tables consists of the code generation rules.
They specify EM patterns, stack patterns, code to be generated etc.
Syntax is
.DS L
code rule : EM pattern '|' stack pattern '|' code '|'
stack replacement '|' EM replacement '|' cost ;
.DE
All parts are optional, however there must be at least one pattern present.
If the empattern is missing the rule becomes a rewriting rule or
.I coercion
to be used when code generation cannot continue
because of an invalid stack pattern.
The code rules are preceded by the word
.DS
CODE:
.DE
The next paragraphs describe the various parts in detail.
.NH 3
The EM pattern
.PP
The EM pattern consists of a list of EM mnemonics followed
by a boolean expression.
Examples:
.DS
\fBloe\fP
.DE
will match a single \fBloe\fP instruction,
.DS
\fBloc\fP \fBloc\fP \fBcif\fP $1==2 && $2==8
.DE
is a pattern that will match
.DS
\fBloc\fP 2
\fBloc\fP 8
\fBcif\fP
.DE
and
.DS
\fBlol\fP \fBinc\fP \fBstl\fP $1==$3
.DE
will match for example
.DS
.ta 10m 20m 30m 40m 50m 60m
\fBlol\fP 6 \fBlol\fP -2 \fBlol\fP 4
\fBinc\fP \fBinc\fP but \fInot\fP \fBinc\fP
\fBstl\fP 6 \fBstl\fP -2 \fBstl\fP -4
.DE
A missing boolean expression evaluates to TRUE.
.PP
When the EM pattern is the same as in the previous code rule the pattern
should be given as `...'.
The code generator will match the longest EM pattern on every occasion,
if two patterns of the same length match the first in the table will be chosen,
while all patterns of length greater than or equal to three are considered
to be of the same length.
.NH 3
The stack pattern
.PP
The stack pattern is a list of token expressions,
usually token expression identifiers for clarity.
No boolean expression is allowed here.
The first expression is the one that matches the top of the stack.
.PP
The pattern can be followed by the word STACK
in which case the pattern only matches if there is nothing
else on the fakestack.
The code generator will stack everything not matched at the start
of the rule.
.PP
The pattern can be preceded with the word
.DS
nocoercions:
.DE
which tells the code generator not to try to coerce to the pattern
but only to use it when it is already there.
There are two reasons for this construction,
correctness and speed.
It is needed for correctness when the pattern contains a register
that is not transparent when data is moved through it.
.PP
Example: on the PDP-11 the shortest code for
.DS
\fBlae\fP a
\fBloi\fP 8
\fBlae\fP b
\fBsti\fP 8
.DE
is
.DS
movf _a,fr0
movf fr0,_b
.DE
assuming that the floating point processor is in double
precision mode and fr0 is free.
Unfortunately this is not correct since a trap can occur on certain
kinds of data.
This could happen if there was a pattern for \fBsti\fP\ 8 that allowed
one to move a floating point register not preceded by nocoercions: .
The code generator would then find that moving the 8-byte global _a
to a floating point register and then storing it to _b was the cheapest,
assuming that the space/time knob was turned far enough to space.
It is unfortunate that the type information is no longer present,
since if _a really is a floating point number the move could be
made without error.
.PP
The second reason for the nocoercions: construct is speed.
When the code generator has a long list of possible stack patterns
for one EM pattern it can waste a lot of time trying to find coercions
to all of them, while the mere presence of such a long list
indicates that the table writer has given a lot of special cases.
In this case prepending all the special cases by nocoercions:
will stop the code generator from trying to find things there aren't.
.NH 3
The code part
.PP
The code part consists of three parts, stack cleanup, register allocation
and code to generate.
All of these may be omitted.
.NH 4
Stack cleanup
.PP
The stack cleanup part describes certain stacktokens that should neither remain on
the fakestack, nor remembered as contents of registers.
This is usually only required with store operations.
The entire fakestack, except for the part matched in the stack pattern,
is searched for tokens matching the expression and they are copied
to the real stack.
Every register that contains the stacktoken is marked as empty.
.PP
Syntax is
.DS
remove(token expression) \fIor\fP
remove(token expression, boolean expression)
.DE
Example:
.DS
remove(REGOFF2,%[reg] != LB || %[off] == $1)
.DE
is part of a remove() call for use in the \fBstl\fP code rule.
It removes all register offsetted tokens where the register is not the
localbase plus the local wherein the store is done.
The necessity for this can be seen from the following example:
.DS
\fBlol\fP 4
\fBinl\fP 4
\fBstl\fP 6
.DE
Without a proper remove() call in the rule for \fBinl\fP code would
be generated as here
.DS
inc 4(r5)
mov 4(r5),6(r5)
.DE
so local 6 would be given the new value of local 4 instead of the old
as the EM code prescribed.
.PP
When generating something like a branch instruction it
might be needed to empty the fakestack completely.
This can of course be done with
.DS
remove(ALL)
.DE
.NH 4
Register allocation
.PP
The register allocation part describes the kind of registers needed.
Syntax for allocate() is
.DS
allocate(itemlist)
.DE
where itemlist is a list of three kinds of things:
.IP 1)
a tokendescription, for example %[1].
.br
This will instruct the code generator to temporarily decrement the reference count
of all registers contained in the token,
so that they are available for allocation in this allocate() call
if they were only used in that token.
See example below.
.IP 2)
a register property.
.br
This will allocate a register with that property.
The register will be marked as empty at this point.
Lookahead will be performed if necessary.
.IP 3)
a register property with initialization.
.br
This will allocate the register as in 2) but will also
initialize it.
This eases the task of the code generator because it can
find a register already filled with the right value
if it exists.
.PP
Examples:
.DS
allocate(OREG)
.DE
will allocate an odd register, while
.DS
allocate(REG={REGOFF2,LB,$1})
.DE
will allocate a register while simultaneously filling it with
the asked value.
.br
Inside the coercion from SOURCE2 to REGISTER in the PDP-11 table
the following allocate() can be found.
.DS
allocate(%[1],REG=%[1])
.DE
This tells the code generator that registers contained in %[1] can be used
again and asks to fill the register allocated with %[1].
So if %[1]={REGOFF2,R3,"4"} and R3 has a reference count of 1
the following code might be generated.
.DS
mov 4(r3),r3
.DE
In the rest of the line the registers allocated can be named by
%[a] and %[b.1],%[b.2], i.e. with lower case letters
in order of allocation.
.PP
Warning:
.DS
allocate(R3)
.DE
is \fRnot\fP the way to allocate R3.
R3 is not a register property, so it will be seen as a token description
and the effect is that R3 will have its reference count decremented.
.NH 4
Code
.PP
Code to be generated is specified as a list of items of the following kind:
.IP 1)
a string in double quotes ("This is a string").
.br
This is copied to the codefile and a newline ( \en ) is appended.
Inside the string all normal C string conventions are allowed,
and substitutions can be made of the following sorts.
.RS
.IP a)
$1, $2 etc.
These are the operands of the corresponding EM instructions
and are printed according to their type.
To put a real '$' inside the string it must be doubled ('$$').
.IP b)
%[1], %[2.reg], %[b.1] etc.
These have their obvious meaning.
If they describe a complete token ( %[1] )
the printformat for the token is used.
If they stand for a basic term in an expression
they will be printed according to their type.
To put a real '%' inside the string it must be doubled ('%%').
.IP c)
%( arbitrary expression %).
This allows inclusion of arbitrary expressions inside strings.
Usually not needed very often,
so that the awkward notation is not too bad.
Note that %(%[1]%) is equivalent to %[1].
.RE
.IP 2)
a move() call.
This has the following syntax:
.DS
move(token description, token description)
.DE
Moves are handled specially since that enables the code generator
to keep track of register contents.
Example:
.DS
move(R3,{REGOFF2,LB,$1})
.DE
will generate code to move R3 to $1(r5) except when
R3 already was a copy of $1(r5).
Then the code will be omitted.
The rules describing how to move things to each other
can be found in the MOVES section described below.
.IP 3)
an erase() call.
This has the following syntax:
.DS
erase(register expression)
.DE
This tells the code generator that the register mentioned no longer has any
useful value.
This is
.I necessary
after code in the table has changed the contents of registers.
For example, after an add to a register the register must be erased,
because the contents do no longer match any token.
.IP 4)
For machines that have condition codes,
alas most of them do,
there are provisions to remember condition code setting
and prevent needless testing.
To set the condition code to a token put in the code the following call:
.DS
test(token)
.DE
where token can be all of the standard forms that can also be used in move().
This will generate a test if the condition codes
were not already set to that token.
It is also possible to tell
.I cg
that a certain operation, like a preceding add
has set the condition codes to some token with the call
.DS
setcc(token)
.DE
So a sequence of a setcc and a test on the same token will generate
no code.
Another allowed call within the code is
.DS
samecc
.DE
which tells the code generator that condition codes were unaffected
in this rule.
If no setcc or samecc has been given the default is
.DS
nocc
.DE
when a piece of code contained strings,
which tells the code generator that the condition codes
have no useful value any more.
.NH 3
Stack replacement
.PP
The stack replacement is a possibly empty list of items to be pushed onto
the fakestack. Three kinds of items are possible:
.IP 1)
An item of the form %[1]. This will push the stacktoken mentioned back
onto the stack unchanged.
.IP 2)
A register expression. This will push the register mentioned
onto the fakestack.
.IP 3)
An item of the form { REGOFF2,%[1.reg],$1 }.
This generates a token with tokenidentifier REGOFF2 and attributes
in order of declaration.
.PP
All tokens matched by the stack pattern at the beginning of the code rule
are first removed and their registers deallocated.
Items are pushed in the order of appearance.
This means that the last item will be on the top of the
stack after the push.
So if the stack pattern contained two token expressions
and they must be pushed back unchanged,
they have to be specified as stack replacement
.DS
%[2] %[1]
.DE
and not the other way around.
.NH 3
EM replacement
.PP
In exceptional cases it might be useful to leave part of an empattern
undone.
For example, a \fBsdl\fP instruction might be split into two \fBstl\fP instructions
when there is no 4-byte quantity on the stack. The emreplacement part allows
one to express this.
Example:
.DS
\fBstl\fP $1 \fBstl\fP $1+2
.DE
The instructions are inserted in the stream so that they can match
the first part of a pattern in the next step.
Note that since the code generator traverses the EM instructions in a strict
linear fashion,
it is impossible to let the EM replacement match later parts of a pattern.
So if there is a pattern
.DS
\fBloc\fP \fBstl\fP $1==0
.DE
and the input is
.DS
\fBloc\fP 0 \fBsdl\fP 4
.DE
the \fBloc\fP\ 0 will be processed first,
then the \fBsdl\fP might be split into two \fBstl\fP's but the pattern
cannot match now.
.NH 3
Cost
.PP
The cost field can be specified when there is more than one
code rule with the same empattern.
If the code generator has a choice between two possibilities
to generate code it will choose the cheapest according to
the cost field.
The cost for a code generation is the sum of the costs
of all the coercions needed, plus the cost for freeing
registers plus the cost of the code rule itself.
.PP
The format of the costfield is
.DS
( nbytes, time ) or
( nbytes, time ) + %[\fIi\fP]
.DE
with time in the metric desired, like nanoseconds or states.
See constants section above.
The %[\fIi\fP] in the second example is used for adding the cost of a certain
address mode used in the code generated.
This can of course be repeated if desired.
The cost of the address mode must then be specified in the token definition
section.
.NH 3
Examples
.PP
A list of examples for the PDP-11 is given here.
Far from being complete it gives examples of most kinds
of instructions.
.DS L
\fBadi\fP $1==2 | SREG,SOURCE2 |
"add %[2],%[1]" erase(%[1]) setcc(%[1])
| %[1] | | (2,450) + %[2]
\&... | SOURCE2,SREG |
"add %[1],%[2]" erase(%[2]) setcc(%[2])
| %[2] | | (2,450) + %[1]
.DE
is an example of the use of the `...' construct
and shows how to place erase() and setcc() calls.
.DS L
\fBdvi\fP $1==2 | SOURCE2,SPAIRSIGNED |
"div %[1],%[2]" erase(%[2])
| %[2.regeven] | |
\fBcmi\fP \fBtgt\fP $1==2 | SOURCE2,SOURCE2 | allocate(REG={CONST,0})
"cmp %[2],%[1];ble 1f;inc %[a];1:" erase(%[a])
| %[a] | |
\fBcal\fP | STACK |
"jsr pc,$1"
| | |
\fBlol\fP | | | { REGOFF2, LB, $1 } | |
\fBstl\fP | SOURCE2 |
remove(REGOFF2,%[off]==$1)
move(%[1],{REGOFF2,LB,$1})
| | |
| SOURCE2 |
allocate(%[1],REGPAIR)
move(%[1],%[a.2])
test(%[a.2])
"sxt %[a.even]" | { PAIRSIGNED, %[a.1], %[a.2] }| |
.DE
This coercion shows how to use the move and test calls.
At first one might think that the testcall is unnecessary,
since the move will have set the condition codes,
but the move may never have been executed
if the register already contained the value,
in which case it is necessary to do the test.
If the move was executed the test will be omitted.
.DS L
| SOURCE2 | allocate(%[1],REG=%[1]) | %[a] | |
\fBsdl\fP | SOURCE2 | | %[1] | \fBstl\fP $1 \fBstl\fP $1+2 |
\fBexg\fP $1==2 | SOURCE2 SOURCE2 | | %[1] %[2] | |
.DE
This last example again shows the difference in the order
of the stack pattern and the stack replacement.
.NH 2
Move code rules
.PP
When issuing a move() call as described above or a register allocation
with initialization, the code generator has to know which
instruction to use for the move.
The code will of course only be generated if it cannot be omitted.
This is listed in the move section of the tables by giving a list
of tuples:
.DS
( source, destination, codepart [ , costfield ] )
.DE
where the square brackets mean the costfield is optional.
Example for the PDP-11
.DS
MOVES:
( CONST %[off]==0 , SOURCE2, "clr %[2]" )
( SOURCE2, SOURCE2, "mov %[1],%[2]" )
.DE
The moves are scanned from top to bottom,
so the first one that matches will be chosen.
.NH 2
Test code rules
.PP
When issuing a test() call as described above,
the code generator has to know which instruction
to use for the test.
The code will only be generated if the condition codes
were not already set to the token.
This is listed in the test section of the tables by giving
a list of tuples:
.DS
( source, codepart [ , costfield ] )
.DE
Example for the PDP-11
.DS
TESTS:
( SOURCE2, "tst %[1]")
( DREG, "tstf %[1]\encfcc")
.DE
The tests are scanned from top to bottom,
so the first one that matches will be chosen.
.NH 2
Stacking code rules.
.PP
When the code generator has to stack a token it must know
which code to use.
Since it must at all times be possible to empty the fakestack
even when no registers are free,
it is mandatory that all
tokens used must have a rule attached for stacking them
without using a scratch register.
Since however this might be clumsy and
a register might in practice be available
it is also possible to give rules
which use a register.
On the Intel 8086 for example,
there is no instruction to push a constant without using a register,
and the code needed to do it without, must use global data
and as such is very complicated and wasteful of memory and time.
It can therefore be left to be used in extreme cases,
while in general the constant is pushed through a register.
The stacking rules are listed in the stack section of the table as a list
of tuples:
.DS
(source, [ register property ] , codepart [ , costfield ] )
.DE
Example for the Intel 8086:
.DS
STACKS:
(CONST, REG, move(%[1],%[a]) "push %[a]")
(REG ,, "push %[1]")
.DE
.NH 1
The files mach.h and mach.c
.PP
The table writer must also supply two files containing
machine dependent declarations and C code.
These files are mach.h and mach.c.
.NH 2
Types in the code generator
.PP
Three different types of integer coexist in the code generator
and their range depends on the machine at hand.
The type 'int' is used for things like labelcounters that won't require
more than 16 bits precision.
The type 'word' is used among others to assemble datawords and
is of type 'long'.
The type 'full' is used for addresses and is of type 'long' if
EM_WSIZE>2 or EM_PSIZE>2.
.PP
In macro and function definitions in later paragraphs implicit typing
will be used for parameters, that is parameters starting with an 's'
will be of type string, and the letters 'i','w','f' will stand for
int, word and full respectively.
.NH 2
Global variables to work with
.PP
Some global variables are present in the code generator
that can be manipulated by the routines in mach.h and mach.c.
.LP
The declarations are:
.DS L
.ta 20
FILE *codefile; /* code is emitted on this stream */
word part_word; /* words to be output are put together here */