summaryrefslogtreecommitdiff
path: root/ghc/includes/COptRegs.lh
blob: eaf46f94aec2c342bc1937d01703cb4ef138866b (plain)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
%
% (c) The GRASP Project, Glasgow University, 1993
%
\section[StgRegs-decls]{STG-machine register mappings}

\begin{code}
#ifndef COPTREGS_H
#define COPTREGS_H

#include "StgMachDeps.h"
#include "StgTypes.h"
#include "MachRegs.h"

#define GLOBAL_REG_DECL(type,name,reg) register type name REG(reg);

\end{code}

Various parts of the GHC system use various sets of ``registers,'' by
which we mean (frequently-used) words of globally-visible information.
For example, the everyday ``Haskell threaded world,'' uses the
``registers'' @Hp@, @R4@, etc., etc.

We would really like to ``steal'' machine registers from the C
execution model (via GCC's global-variable-in-register extension) and
map some/all of our ``STG registers'' onto real machine registers.
This has a profound benefit in terms of execution speed.

This file/document/section sets out the various (machine-dependent)
mappings that we use.

Note: for one machine, there are {\em several} possible register
mappings, {\em one} of which is in force at any time.  Obviously, the
``main'' mapping (used in the Haskell threaded world) dominates, but
when garbage-collecting (for example), we'd rather not tie up all
those registers in that way (i.e., for global-variables that aren't
used in the GC). Instead, we'd rather bring in {\em another} register
mapping, tuned to the needs of a particular (isolated) bit of C code.
As there are several garbage collectors there are quite a few possible
mappings.

%************************************************************************
%*									*
\subsection[saved-STG-regs]{Saved STG registers}
%*									*
%************************************************************************

The following stuff is available regardless of register map.  It allows
us access to the saved STG registers from other parts of the RTS (notably
from the storage manager).

\begin{code}

typedef struct rt {
    StgDouble rDbl[2];	/* Put a double first to ensure expected alignment */
    StgFloat rFlt[4];
    StgUnion rR[8];
    PP_ rSpA;
    PP_ rSuA;
    P_ rSpB;
    P_ rSuB;
    P_ rHp;
    P_ rHpLim;
    I_ rTag;
    StgRetAddr rRet;
    I_ rActivity;	/* NB: UNUSED */
    P_ rCstkptr;	/* used for iX86 registerizing only! offset=100 */
    P_ rWrapReturn;	/* ditto; offset=104 */
    P_ rSaveECX;	/* ditto; offset=108 */
#if defined(CONCURRENT)
    P_ rStkO;
    I_ rLiveness;
#endif
} STGRegisterTable;

\end{code}

There are several confusing macro sets for accessing STG registers at various
stages in their lives.  


The MAIN_* macros refer to the save locations for the main thread.
These are generally useful when the main thread is suspended.  Note
that the save locations for S[up][AB] are actually in the pseudo stack
object, MainStkO, when running threads.

The SAVE_* macros refer to the save locations for the current thread,
without using BaseReg.  These are used when we cannot be sure that any
STG registers are actually loaded in machine registers.

The RTBL_* macros refer to the register table locations for the current
thread, indexed from BaseReg.  If BaseReg is in a machine register, that
register {\em must} be loaded with the address of the register table.

OK, now... In the sequential world at least, each of those
``register'' declarations also set up a ``backup'' location; for
register @r@, the backup location (a global variable) is @r_SAVE@.

We need @SAVE_STG_REGS@ and @RESTORE_STG_REGS@ macros, which copy back
and forth between the ``registers'' and their \tr{*_SAVE} backup
locations.

In the parallel world, we have the closely-related business of
saving/restoring ``thread state''.  We do it in two stages:
save/restore to/from \tr{*_SAVE} locations, then fill in the
``thread-state object'' (TSO) from the \tr{*_SAVE} locations.  (This
means the thread-state saving can more easily be written in C, rather
than assembler.)

Why no space to save BaseReg?  Because either (1) if in a caller-save
register, the caller will have saved it; or (2) if in a callee-save
register, the miniInterpret machinery will have saved it.  This works
because we entered ``threaded Haskell land'' in a v disciplined
way---i.e., via miniInterpret.

However, the bits of code that use the various GC register maps (SCAV,
MARK, SCAN) are called in less-disciplined ways, so their base-regs
need saving/restoring.  (WDP 95/02)

\begin{code}

#ifndef PAR
extern STGRegisterTable MainRegTable;
#endif	/* PAR */

/* these are for the main register table */
#define MAIN_R1     	    (MainRegTable.rR[0])
#define MAIN_R2     	    (MainRegTable.rR[1])
#define MAIN_R3     	    (MainRegTable.rR[2])
#define MAIN_R4     	    (MainRegTable.rR[3])
#define MAIN_R5     	    (MainRegTable.rR[4])
#define MAIN_R6     	    (MainRegTable.rR[5])
#define MAIN_R7     	    (MainRegTable.rR[6])
#define MAIN_R8     	    (MainRegTable.rR[7])
#define MAIN_Flt1   	    (MainRegTable.rFlt[0])
#define MAIN_Flt2   	    (MainRegTable.rFlt[1])
#define MAIN_Flt3   	    (MainRegTable.rFlt[2])
#define MAIN_Flt4   	    (MainRegTable.rFlt[3])
#define MAIN_Dbl1   	    (MainRegTable.rDbl[0])
#define MAIN_Dbl2   	    (MainRegTable.rDbl[1])

#define MAIN_Hp    	    (MainRegTable.rHp)
#define MAIN_HpLim    	    (MainRegTable.rHpLim)
#define MAIN_Tag    	    (MainRegTable.rTag)
#define MAIN_Ret    	    (MainRegTable.rRet)

#define MAIN_StkO   	    (MainStkO)
#define MAIN_Liveness 	    (MainRegTable.rLiveness)

#ifndef CONCURRENT

#define MAIN_SpA    	    (MainRegTable.rSpA)
#define MAIN_SuA    	    (MainRegTable.rSuA)
#define MAIN_SpB    	    (MainRegTable.rSpB)
#define MAIN_SuB    	    (MainRegTable.rSuB)

/* these are really for *SAVE*ing */
#define SAVE_R1     	    MAIN_R1
#define SAVE_R2     	    MAIN_R2
#define SAVE_R3     	    MAIN_R3
#define SAVE_R4     	    MAIN_R4
#define SAVE_R5     	    MAIN_R5
#define SAVE_R6     	    MAIN_R6
#define SAVE_R7     	    MAIN_R7
#define SAVE_R8     	    MAIN_R8
#define SAVE_Flt1   	    MAIN_Flt1
#define SAVE_Flt2   	    MAIN_Flt2
#define SAVE_Flt3   	    MAIN_Flt3
#define SAVE_Flt4   	    MAIN_Flt4
#define SAVE_Dbl1   	    MAIN_Dbl1
#define SAVE_Dbl2   	    MAIN_Dbl2
			    
#define SAVE_SpA    	    MAIN_SpA
#define SAVE_SuA    	    MAIN_SuA
#define SAVE_SpB    	    MAIN_SpB
#define SAVE_SuB    	    MAIN_SuB
			    
#define SAVE_Tag    	    MAIN_Tag
#define SAVE_Ret    	    MAIN_Ret

#else

extern P_ MainStkO;

#define MAIN_SpA    	    (STKO_SpA(MainStkO))
#define MAIN_SuA    	    (STKO_SuA(MainStkO))
#define MAIN_SpB    	    (STKO_SpB(MainStkO))
#define MAIN_SuB    	    (STKO_SuB(MainStkO))

extern STGRegisterTable *CurrentRegTable;

/* these are really for *SAVE*ing */
#define SAVE_R1     	    (CurrentRegTable->rR[0])
#define SAVE_R2     	    (CurrentRegTable->rR[1])
#define SAVE_R3     	    (CurrentRegTable->rR[2])
#define SAVE_R4     	    (CurrentRegTable->rR[3])
#define SAVE_R5     	    (CurrentRegTable->rR[4])
#define SAVE_R6     	    (CurrentRegTable->rR[5])
#define SAVE_R7     	    (CurrentRegTable->rR[6])
#define SAVE_R8     	    (CurrentRegTable->rR[7])
#define SAVE_Flt1   	    (CurrentRegTable->rFlt[0])
#define SAVE_Flt2   	    (CurrentRegTable->rFlt[1])
#define SAVE_Flt3   	    (CurrentRegTable->rFlt[2])
#define SAVE_Flt4   	    (CurrentRegTable->rFlt[3])
#define SAVE_Dbl1   	    (CurrentRegTable->rDbl[0])
#define SAVE_Dbl2   	    (CurrentRegTable->rDbl[1])

/* These are only valid when StkOReg is loaded! */

#define SAVE_SpA    	    (STKO_SpA(StkOReg))
#define SAVE_SuA    	    (STKO_SuA(StkOReg))
#define SAVE_SpB    	    (STKO_SpB(StkOReg))
#define SAVE_SuB    	    (STKO_SuB(StkOReg))

#define SAVE_Tag    	    (CurrentRegTable->rTag)
#define SAVE_Ret    	    (CurrentRegTable->rRet)

#define SAVE_StkO   	    (CurrentRegTable->rStkO)
#define SAVE_Liveness 	    (CurrentRegTable->rLiveness)

#endif	/* CONCURRENT */

/* Note that the SAVE_ locations for the Hp registers are in the smInfo structure */

#define SAVE_Hp	    	    (StorageMgrInfo.hp)
#define SAVE_HpLim	    (StorageMgrInfo.hplim)

\end{code}

%************************************************************************
%*									*
\subsection[null-mapping-StgRegs]{The empty register mapping}
%*									*
%************************************************************************

This mapping leaves all machine registers free for normal C allocation.
In the RTS, this is the preferred mapping, because it allows gcc to use
all available registers, with the normal callee-saves conventions.
\begin{code}
#if defined(NULL_REG_MAP)
#else
\end{code}

This is a HACK here; see comment in COptJumps.lh.
\begin{code}
#if alpha_dec_osf1_TARGET && defined(__STG_TAILJUMPS__) && defined(__GNUC__)
register void *_procedure __asm__("$27");
#endif
#if (mipsel_TARGET_ARCH || mipseb_TARGET_ARCH) && defined(__STG_TAILJUMPS__) && defined(__GNUC__)
register void *_procedure __asm__("$25");
#endif
\end{code}

%************************************************************************
%*									*
\subsection[mark-mapping-StgRegs]{The ``mark'' register mapping}
%*									*
%************************************************************************

The mark mapping is used for pointer-reversal marking during GC.  It
is used by most of the current garbage collectors.

\begin{code}
#if defined(MARK_REG_MAP)
\end{code}

Mark (GC) register mapping:

\begin{verbatim}
	    	sparc  m68k  alpha  mipseX  hppa  iX86  powerpc
        	-----  ----  -----  ------  ----  ----  -------
MarkBase					  ebx
		
Mark	    	i0     a2    $9	    $16	    r4	  ebp
MStack	    	i1     a3    $10    $17	    r5    esi
MRoot  		i2     a4    $11    $18	    r6	  edi
BitArray    	i3     a5    $12    $19	    r7
HeapBase    	i4     d3    $13    $20	    r8
HeapLim	    	i5     d4    $14    $21	    r9

\end{verbatim}

\begin{code}

typedef struct {
    P_ rMark;
    P_ rMStack;
    P_ rMRoot;
    BitWord *rBitArray;
    P_ rHeapBase;
    P_ rHeapLim;
    P_ rMarkBase;
} RegisterTable;

#define REGDUMP(dump)	static RegisterTable dump

#define SAVE_Mark   	(MarkRegTable.rMark)
#define SAVE_MStack    	(MarkRegTable.rMStack)
#define SAVE_MRoot  	(MarkRegTable.rMRoot)
#define SAVE_BitArray	(MarkRegTable.rBitArray)
#define SAVE_HeapBase	(MarkRegTable.rHeapBase)
#define SAVE_HeapLim	(MarkRegTable.rHeapLim)

extern RegisterTable MarkRegTable;

#ifdef REG_MarkBase
GLOBAL_REG_DECL(RegisterTable *,MarkBaseReg,REG_MarkBase)
#else
#define MarkBaseReg (&MarkRegTable)
#endif

#ifdef REG_Mark
GLOBAL_REG_DECL(P_,Mark,REG_Mark)
#else
#define Mark SAVE_Mark
#endif

#ifdef REG_MStack
GLOBAL_REG_DECL(P_,MStack,REG_MStack)
#else
#define MStack SAVE_MStack
#endif

#ifdef REG_MRoot
GLOBAL_REG_DECL(P_,MRoot,REG_MRoot)
#else
#define MRoot SAVE_MRoot
#endif

#ifdef REG_BitArray
GLOBAL_REG_DECL(P_,BitArray,REG_BitArray)
#else
#define BitArray SAVE_BitArray
#endif

#ifdef REG_HeapBase
GLOBAL_REG_DECL(P_,HeapBase,REG_HeapBase)
#else
#define HeapBase SAVE_HeapBase
#endif

#ifdef REG_HeapLim
GLOBAL_REG_DECL(P_,HeapLim,REG_HeapLim)
#else
#define HeapLim SAVE_HeapLim
#endif

#if defined(__STG_GCC_REGS__)
/* Keep -Wmissing-prototypes from complaining */
void SAVE_REGS    PROTO((RegisterTable *dump));
void RESTORE_REGS PROTO((RegisterTable *dump));

extern STG_INLINE 
void SAVE_REGS(dump)
RegisterTable *dump;
{
#ifdef REG_MarkBase
    dump->rMarkBase = (P_) MarkBaseReg; /* save whatever is in it */
    MarkBaseReg = dump; /* set it correctly */
#endif
#ifdef REG_Mark    
    dump->rMark = Mark;
#endif
#ifdef REG_MStack
    dump->rMStack = MStack;
#endif
#ifdef REG_MRoot
    dump->rMRoot = MRoot;
#endif
#ifdef REG_BitArray
    dump->rBitArray = BitArray;
#endif
#ifdef REG_HeapBase
    dump->rHeapBase = HeapBase;
#endif
#ifdef REG_HeapLim
    dump->rHeapLim = HeapLim;
#endif
}

extern STG_INLINE 
void RESTORE_REGS(dump)
RegisterTable *dump;
{
#ifdef REG_Mark    
    Mark = dump->rMark;
#endif
#ifdef REG_MStack
    MStack = dump->rMStack;
#endif
#ifdef REG_MRoot
    MRoot = dump->rMRoot;
#endif
#ifdef REG_BitArray
    BitArray = dump->rBitArray;
#endif
#ifdef REG_HeapBase
    HeapBase = dump->rHeapBase;
#endif
#ifdef REG_HeapLim
    HeapLim = dump->rHeapLim;
#endif
#ifdef REG_MarkBase
    MarkBaseReg = (RegisterTable *) dump->rMarkBase; /* restore to whatever it was */
#endif
}
#else
#define SAVE_REGS(dump)
#define RESTORE_REGS(dump)
#endif
\end{code}

%************************************************************************
%*									*
\subsection[scan-mapping-StgRegs]{The ``scan'' register mapping}
%*									*
%************************************************************************

The scan mapping is used for all of the in-place garbage collectors.
On architectures with register windows, like the SPARC, these must
reside in global registers, because the scan code is not threaded.

\begin{code}
#else
#if defined(SCAN_REG_MAP)
\end{code}

Scan (GC) register mapping:

\begin{verbatim}
	    	sparc  m68k  alpha  mipseX  hppa  iX86  powerpc
        	-----  ----  -----  ------  ----  ----  -------
ScanBase   	g4
		
Scan	    	       a2    $9	    $16	    r4    ebx
New	    	       a3    $10    $17	    r5	  ebp
LinkLim		       a4    $11    $18	    r6	  esi

\end{verbatim}

\begin{code}

typedef struct {
    P_ rScan;
    P_ rNew;
    P_ rLinkLim;
    P_ rScanBase;
} RegisterTable;
    
#define REGDUMP(dump)	static RegisterTable dump

#define SAVE_Scan   	(ScanRegTable.rScan)
#define SAVE_New    	(ScanRegTable.rNew)
#define SAVE_LinkLim  	(ScanRegTable.rLinkLim)

extern RegisterTable ScanRegTable;

#ifdef REG_ScanBase
GLOBAL_REG_DECL(RegisterTable *,ScanBaseReg,REG_ScanBase)
#else
#define ScanBaseReg (&ScanRegTable)
#endif

#ifdef REG_Scan
GLOBAL_REG_DECL(P_,Scan,REG_Scan)
#else
# ifdef REG_ScanBase
#  define Scan (ScanBaseReg->rScan)
# else
#  define Scan SAVE_Scan
# endif
#endif

#ifdef REG_New
GLOBAL_REG_DECL(P_,New,REG_New)
#else
# ifdef REG_ScanBase
#  define New (ScanBaseReg->rNew)
# else
#  define New SAVE_New
# endif
#endif

#ifdef REG_LinkLim
GLOBAL_REG_DECL(P_,LinkLim,REG_LinkLim)
#else
# ifdef REG_ScanBase
#  define LinkLim (ScanBaseReg->rLinkLim)
# else
#  define LinkLim SAVE_LinkLim
# endif
#endif

#if defined(__STG_GCC_REGS__)
/* Keep -Wmissing-prototypes from complaining */
void SAVE_REGS    PROTO((RegisterTable *dump));
void RESTORE_REGS PROTO((RegisterTable *dump));

extern STG_INLINE 
void SAVE_REGS(dump)
RegisterTable *dump;
{
#ifdef REG_ScanBase
    dump->rScanBase = (P_) ScanBaseReg; /* save whatever is in it */
    ScanBaseReg = dump; /* set it correctly */
#endif
#ifdef REG_Scan    
    dump->rScan = Scan;
#endif
#ifdef REG_New
    dump->rNew = New;
#endif
#ifdef REG_LinkLim
    dump->rLinkLim = LinkLim;
#endif
}

extern STG_INLINE 
void RESTORE_REGS(dump)
RegisterTable *dump;
{
#ifdef REG_Scan    
    Scan = dump->rScan;
#endif
#ifdef REG_New
    New = dump->rNew;
#endif
#ifdef REG_LinkLim
    LinkLim = dump->rLinkLim;
#endif
#ifdef REG_ScanBase
    ScanBaseReg = (RegisterTable *) dump->rScanBase; /* restore to whatever it was */
#endif
}
#else
#define SAVE_REGS(dump)
#define RESTORE_REGS(dump)
#endif
\end{code}

%************************************************************************
%*									*
\subsection[scav-mapping-StgRegs]{The ``scavenge'' register mapping}
%*									*
%************************************************************************

The scan mapping is used for all of the in-place garbage collectors.
(I believe that it must use a subset of the registers that are used
in the mark mapping, but I could be wrong. --JSM)

Note: registers must not be mangled by sliding register windows,
etc. or there'll be trouble. ADR

\begin{code}
#else
#if defined(SCAV_REG_MAP)
\end{code}

Scavenge (GC) register mapping:

\begin{verbatim}
	    	sparc  m68k  alpha  mipseX  hppa  iX86  powerpc
        	-----  ----  -----  ------  ----  ----  -------
ScavBase   	g4
		
Scav	    	       a2    $9	    $16	    r4    ebx
ToHp	    	       a3    $10    $17	    r5	  ebp
OldGen (gn/ap)	       a4    $11    $18	    r6	  esi
AllocGen (gn)  	       a5
OldHp	 (gn)  	       d3

\end{verbatim}

(Calling this struct @ScavRegisterTable@ would make it possible for
@gdb@ to display it properly. At the moment, @gdb@ confuses it with
the scan register table etc. ADR )

\begin{code}

typedef struct {
    P_ rScav;
    P_ rToHp;
    P_ rOldGen;
#ifdef GCgn
    P_ rAllocGen;
    P_ rOldHp;
#endif
    P_ rScavBase;
} RegisterTable;

#define REGDUMP(dump)	static RegisterTable dump

#define SAVE_Scav   	(ScavRegTable.rScav)
#define SAVE_ToHp    	(ScavRegTable.rToHp)
#define SAVE_OldGen  	(ScavRegTable.rOldGen)
#define SAVE_AllocGen  	(ScavRegTable.rAllocGen)
#define SAVE_OldHp  	(ScavRegTable.rOldHp)

extern RegisterTable ScavRegTable;

#ifdef REG_ScavBase
GLOBAL_REG_DECL(RegisterTable *,ScavBaseReg,REG_ScavBase)
#else
#define ScavBaseReg (&ScavRegTable)
#endif

#ifdef REG_Scav
GLOBAL_REG_DECL(P_,Scav,REG_Scav)
#else
# ifdef REG_ScavBase
#  define Scav (ScavBaseReg->rScav)
# else
#  define Scav SAVE_Scav
# endif
#endif

#ifdef REG_ToHp
GLOBAL_REG_DECL(P_,ToHp,REG_ToHp)
#else
# ifdef REG_ScavBase
#  define ToHp (ScavBaseReg->rToHp)
# else
#  define ToHp SAVE_ToHp
# endif
#endif

#ifdef REG_OldGen
GLOBAL_REG_DECL(P_,OldGen,REG_OldGen)
#else
# ifdef REG_ScavBase
#  define OldGen (ScavBaseReg->rOldGen)
# else
#  define OldGen SAVE_OldGen
# endif
#endif

#ifdef REG_AllocGen
GLOBAL_REG_DECL(P_,AllocGen,REG_AllocGen)
#else
# ifdef REG_ScavBase
#  define AllocGen (ScavBaseReg->rAllocGen)
# else
#  define AllocGen SAVE_AllocGen
# endif
#endif

#ifdef REG_OldHp
GLOBAL_REG_DECL(P_,OldHp,REG_OldHp)
#else
# ifdef REG_ScavBase
#  define OldHp (ScavBaseReg->rOldHp)
# else
#  define OldHp SAVE_OldHp
# endif
#endif

#if defined(__STG_GCC_REGS__)
/* Keep -Wmissing-prototypes from complaining */
void SAVE_REGS    PROTO((RegisterTable *dump));
void RESTORE_REGS PROTO((RegisterTable *dump));

extern STG_INLINE 
void SAVE_REGS(dump)
RegisterTable *dump;
{
#ifdef REG_ScavBase
    dump->rScavBase = (P_) ScavBaseReg; /* save whatever is in it */
    ScavBaseReg = dump; /* set it correctly */
#endif
#ifdef REG_Scav    
    dump->rScav = Scav;
#endif
#ifdef REG_ToHp
    dump->rToHp = ToHp;
#endif
#ifdef REG_OldGen
    dump->rOldGen = OldGen;
#endif
#ifdef REG_AllocGen
    dump->rAllocGen = AllocGen;
#endif
#ifdef REG_OldHp
    dump->rOldHp = OldHp;
#endif
}

extern STG_INLINE 
void RESTORE_REGS(dump)
RegisterTable *dump;
{
#ifdef REG_Scav    
    Scav = dump->rScav;
#endif
#ifdef REG_ToHp
    ToHp = dump->rToHp;
#endif
#ifdef REG_OldGen
    OldGen = dump->rOldGen;
#endif
#ifdef REG_AllocGen
    AllocGen = dump->rAllocGen;
#endif
#ifdef REG_OldHp
    OldHp = dump->rOldHp;
#endif
#ifdef REG_ScavBase
    ScavBaseReg = (RegisterTable *) dump->rScavBase; /* restore to whatever it was */
#endif
}
#else
#define SAVE_REGS(dump)
#define RESTORE_REGS(dump)
#endif
\end{code}

%************************************************************************
%*									*
\subsection[main-mapping-StgRegs]{The main register mapping (Haskell threaded world)}
%*									*
%************************************************************************

\begin{code}
#else	/* For simplicity, the default is MAIN_REG_MAP (this one) */
\end{code}

Main register-mapping summary: (1)~Specific architecture's details are
given later.  (2)~Entries marked \tr{!} are caller-saves registers
that {\em must be saved} across ccalls; those marked \tr{@} are
caller-saves registers that need {\em not} be saved; those marked
\tr{#} are caller-saves registers that need to be restored, but don't
need to be saved; the rest are callee-save registers (the best kind).

IF YOU CHANGE THIS TABLE, YOU MAY NEED TO CHANGE CallWrapper.s
(or equiv) and [who knows?] maybe something else.  Check the
documentation in the porter's part of the installation guide.

\begin{verbatim}
                sparc  m68k  alpha  mipseX  hppa   iX86  powerpc
                -----  ----  -----  ------  ----   ----  -------
BaseReg#               a5                          ebx

StkOReg								(CONCURRENT)       
		      
R1/Node         l1     d7    $1!    $9!     %r11
R2              l2     d6    $2!    $10!    %r12
R3              l3     d5    $3!    $11!    %r13
R4              l4           $4!    $12!    %r14
R5              l5           $5!    $13!    %r15
R6              l6	     $6!    $14!    %r16
R7              l7           $7!    $15!    %r17
R8                  	     $8!    $24!    %r18

TagReg@

FltReg1         f2!    fp2   $f1    $f20    %fr12
FltReg2         f3!    fp3   $f2    $f22    %fr12R
FltReg3         f4!    fp4   $f3    $f24    %fr13
FltReg4         f5!    fp5   $f4    $f26    %fr13R
		      
DblReg1         f6!    fp6   $f5    $f28    %fr20		* SEE NOTES!
DblReg2         f8!    fp7   $f6    $f30    %fr20		* SEE NOTES!
		      
SpA             i0     a3    $9     $16     %r4
SuA             i1     d3    $10    $17     %r5
SpB             i2     a4    $11    $18     %r6
SuB             i3     d4    $12    $19     %r7

Hp              i4     a2    $13    $20     %r8
HpLim           i5           $14    $21     %r9

RetReg	    	l0           $15    $22	    %r10

Liveness							(CONCURRENT)  

StdUpdRetVec#
StkStub#        i7                  $23
\end{verbatim}

Notes:
\begin{enumerate}
\item
Registers not mentioned in the summary table end up in the default
(a memory location in @MainRegTable@).

\item
@BaseReg@ is in a machine register if anything is (well, unless everything is!)
It points to a block of memory in which the things which don't end up in machine
registers live.

\item
Exceptions to previous point:
If the following labels are in machine registers, then the
corresponding register name refers to what's in its register; otherwise,
it refers to the label:
\begin{verbatim}
StdUpdRetVecReg	vtbl_StdUpdFrame
StkStubReg	STK_STUB_closure
\end{verbatim}
Also, if TagReg is not in a machine register, its name refers to
@INFO_TAG(InfoPtr)@, the tag field from the info table pointed to by
register R2 (InfoPtr).

\end{enumerate}

Next, we have the code to declare the various global registers.  Those
STG registers which don't actually live in machine registers are
defined as macros which refer to the registers as fixed offsets into
the register table.  Note that the register table will contain blank
spots for the STG registers that reside in machine registers.  Not to
worry; these blank spots will be filled in whenever the register
context is saved, so the space does not go to waste.

\begin{code}

#define Node	(R1.p)
#define InfoPtr (R2.d)

/* these are if we get stuck using the reg-tbl "register" (no machine reg avail) */
#define RTBL_Dbl1   	    (BaseReg->rDbl[0])
#define RTBL_Dbl2   	    (BaseReg->rDbl[1])
#define RTBL_Flt1   	    (BaseReg->rFlt[0])
#define RTBL_Flt2   	    (BaseReg->rFlt[1])
#define RTBL_Flt3   	    (BaseReg->rFlt[2])
#define RTBL_Flt4   	    (BaseReg->rFlt[3])
#define RTBL_R1     	    (BaseReg->rR[0])
#define RTBL_R2     	    (BaseReg->rR[1])
#define RTBL_R3     	    (BaseReg->rR[2])
#define RTBL_R4     	    (BaseReg->rR[3])
#define RTBL_R5     	    (BaseReg->rR[4])
#define RTBL_R6     	    (BaseReg->rR[5])
#define RTBL_R7     	    (BaseReg->rR[6])
#define RTBL_R8     	    (BaseReg->rR[7])
#define RTBL_SpA    	    (BaseReg->rSpA)
#define RTBL_SuA    	    (BaseReg->rSuA)
#define RTBL_SpB    	    (BaseReg->rSpB)
#define RTBL_SuB    	    (BaseReg->rSuB)
#define RTBL_Hp     	    (BaseReg->rHp)
#define RTBL_HpLim  	    (BaseReg->rHpLim)
#define RTBL_Tag    	    (BaseReg->rTag)
#define RTBL_Ret    	    (BaseReg->rRet)
#define RTBL_StkO   	    (BaseReg->rStkO)
#define RTBL_Liveness 	    (BaseReg->rLiveness)

#ifdef REG_Base
GLOBAL_REG_DECL(STGRegisterTable *,BaseReg,REG_Base)
#else
#ifdef CONCURRENT
#define BaseReg CurrentRegTable
#else
#define BaseReg (&MainRegTable)
#endif	/* CONCURRENT */
#endif /* REG_Base */

#ifdef REG_StkO
GLOBAL_REG_DECL(P_,StkOReg,REG_StkO)
#else
#define StkOReg RTBL_StkO
#endif

#ifndef __STG_REGS_AVAIL__ /* driver ensures it is 2 or more */
# define __STG_REGS_AVAIL__ 8 /* R1 to R8 */
/* this would only be non-8 if doing weird experiments (WDP 95/11) */
/* or it might be set lower for a particular arch... */
#endif

/* R1 is used for Node */
#ifdef REG_R1
GLOBAL_REG_DECL(StgUnion,R1,REG_R1)
#else
#define R1 RTBL_R1
#endif

/* R2 is used for InfoPtr */
#ifdef REG_R2
GLOBAL_REG_DECL(StgUnion,R2,REG_R2)
#else
#define R2 RTBL_R2
#endif

#ifdef REG_R3
GLOBAL_REG_DECL(StgUnion,R3,REG_R3)
#else
# define R3 RTBL_R3
#endif

#ifdef REG_R4
GLOBAL_REG_DECL(StgUnion,R4,REG_R4)
#else
# define R4 RTBL_R4
#endif

#ifdef REG_R5
GLOBAL_REG_DECL(StgUnion,R5,REG_R5)
#else
# define R5 RTBL_R5
#endif

#ifdef REG_R6
GLOBAL_REG_DECL(StgUnion,R6,REG_R6)
#else
# define R6 RTBL_R6
#endif

#ifdef REG_R7
GLOBAL_REG_DECL(StgUnion,R7,REG_R7)
#else
# define R7 RTBL_R7
#endif

#ifdef REG_R8
GLOBAL_REG_DECL(StgUnion,R8,REG_R8)
#else
# define R8 RTBL_R8
#endif

#ifdef REG_Flt1
GLOBAL_REG_DECL(StgFloat,FltReg1,REG_Flt1)
#else
#define FltReg1 RTBL_Flt1
#endif

#ifdef REG_Flt2
GLOBAL_REG_DECL(StgFloat,FltReg2,REG_Flt2)
#else
#define FltReg2 RTBL_Flt2
#endif

#ifdef REG_Flt3
GLOBAL_REG_DECL(StgFloat,FltReg3,REG_Flt3)
#else
#define FltReg3 RTBL_Flt3
#endif

#ifdef REG_Flt4
GLOBAL_REG_DECL(StgFloat,FltReg4,REG_Flt4)
#else
#define FltReg4 RTBL_Flt4
#endif

#ifdef REG_Dbl1
GLOBAL_REG_DECL(StgDouble,DblReg1,REG_Dbl1)
#else
#define DblReg1 RTBL_Dbl1
#endif

#ifdef REG_Dbl2
GLOBAL_REG_DECL(StgDouble,DblReg2,REG_Dbl2)
#else
#define DblReg2 RTBL_Dbl2
#endif

#ifdef REG_Tag
GLOBAL_REG_DECL(I_,TagReg,REG_Tag)

#define SET_TAG(tag)	TagReg = tag
#else
#define TagReg INFO_TAG(InfoPtr)
#define SET_TAG(tag)	/* nothing */
#endif

#ifdef REG_Ret
GLOBAL_REG_DECL(StgRetAddr,RetReg,REG_Ret)
#else
#define RetReg RTBL_Ret
#endif

#ifdef REG_SpA
GLOBAL_REG_DECL(PP_,SpA,REG_SpA)
#else
#define SpA RTBL_SpA
#endif

#ifdef REG_SuA
GLOBAL_REG_DECL(PP_,SuA,REG_SuA)
#else
#define SuA RTBL_SuA
#endif

#ifdef REG_SpB
GLOBAL_REG_DECL(P_,SpB,REG_SpB)
#else
#define SpB RTBL_SpB
#endif

#ifdef REG_SuB
GLOBAL_REG_DECL(P_,SuB,REG_SuB)
#else
#define SuB RTBL_SuB
#endif

#ifdef REG_Hp
GLOBAL_REG_DECL(P_,Hp,REG_Hp)
#else
#define Hp RTBL_Hp
#endif

#ifdef REG_HpLim
GLOBAL_REG_DECL(P_,HpLim,REG_HpLim)
#else
#define HpLim RTBL_HpLim
#endif

#ifdef REG_Liveness
GLOBAL_REG_DECL(I_,LivenessReg,REG_Liveness)
#else
#define LivenessReg RTBL_Liveness
#endif

#ifdef REG_StdUpdRetVec
GLOBAL_REG_DECL(D_,StdUpdRetVecReg,REG_StdUpdRetVec)
#else
#define StdUpdRetVecReg vtbl_StdUpdFrame
#endif

#ifdef REG_StkStub
GLOBAL_REG_DECL(P_,StkStubReg,REG_StkStub)
#else
#define StkStubReg STK_STUB_closure
#endif

#ifdef CALLER_SAVES_StkO
#define CALLER_SAVE_StkO    	SAVE_StkO = StkOReg;
#define CALLER_RESTORE_StkO 	StkOReg = SAVE_StkO;
#else
#define CALLER_SAVE_StkO    	/* nothing */
#define CALLER_RESTORE_StkO    	/* nothing */
#endif

#ifdef CALLER_SAVES_R1
#define CALLER_SAVE_R1    	SAVE_R1 = R1;
#define CALLER_RESTORE_R1 	R1 = SAVE_R1;
#else
#define CALLER_SAVE_R1      	/* nothing */
#define CALLER_RESTORE_R1    	/* nothing */
#endif

#ifdef CALLER_SAVES_R2
#define CALLER_SAVE_R2    	SAVE_R2 = R2;
#define CALLER_RESTORE_R2 	R2 = SAVE_R2;
#else
#define CALLER_SAVE_R2      	/* nothing */
#define CALLER_RESTORE_R2    	/* nothing */
#endif

#ifdef CALLER_SAVES_R3
#define CALLER_SAVE_R3    	SAVE_R3 = R3;
#define CALLER_RESTORE_R3 	R3 = SAVE_R3;
#else
#define CALLER_SAVE_R3      	/* nothing */
#define CALLER_RESTORE_R3    	/* nothing */
#endif

#ifdef CALLER_SAVES_R4
#define CALLER_SAVE_R4    	SAVE_R4 = R4;
#define CALLER_RESTORE_R4 	R4 = SAVE_R4;
#else
#define CALLER_SAVE_R4      	/* nothing */
#define CALLER_RESTORE_R4    	/* nothing */
#endif

#ifdef CALLER_SAVES_R5
#define CALLER_SAVE_R5    	SAVE_R5 = R5;
#define CALLER_RESTORE_R5 	R5 = SAVE_R5;
#else
#define CALLER_SAVE_R5      	/* nothing */
#define CALLER_RESTORE_R5    	/* nothing */
#endif

#ifdef CALLER_SAVES_R6
#define CALLER_SAVE_R6    	SAVE_R6 = R6;
#define CALLER_RESTORE_R6 	R6 = SAVE_R6;
#else
#define CALLER_SAVE_R6      	/* nothing */
#define CALLER_RESTORE_R6    	/* nothing */
#endif

#ifdef CALLER_SAVES_R7
#define CALLER_SAVE_R7    	SAVE_R7 = R7;
#define CALLER_RESTORE_R7 	R7 = SAVE_R7;
#else
#define CALLER_SAVE_R7      	/* nothing */
#define CALLER_RESTORE_R7    	/* nothing */
#endif

#ifdef CALLER_SAVES_R8
#define CALLER_SAVE_R8    	SAVE_R8 = R8;
#define CALLER_RESTORE_R8 	R8 = SAVE_R8;
#else
#define CALLER_SAVE_R8      	/* nothing */
#define CALLER_RESTORE_R8    	/* nothing */
#endif

#ifdef CALLER_SAVES_FltReg1
#define CALLER_SAVE_FltReg1    	SAVE_Flt1 = FltReg1;
#define CALLER_RESTORE_FltReg1 	FltReg1 = SAVE_Flt1;
#else
#define CALLER_SAVE_FltReg1    	/* nothing */
#define CALLER_RESTORE_FltReg1 	/* nothing */
#endif

#ifdef CALLER_SAVES_FltReg2
#define CALLER_SAVE_FltReg2    	SAVE_Flt2 = FltReg2;
#define CALLER_RESTORE_FltReg2 	FltReg2 = SAVE_Flt2;
#else
#define CALLER_SAVE_FltReg2    	/* nothing */
#define CALLER_RESTORE_FltReg2 	/* nothing */
#endif

#ifdef CALLER_SAVES_FltReg3
#define CALLER_SAVE_FltReg3    	SAVE_Flt3 = FltReg3;
#define CALLER_RESTORE_FltReg3 	FltReg3 = SAVE_Flt3;
#else
#define CALLER_SAVE_FltReg3    	/* nothing */
#define CALLER_RESTORE_FltReg3 	/* nothing */
#endif

#ifdef CALLER_SAVES_FltReg4
#define CALLER_SAVE_FltReg4    	SAVE_Flt4 = FltReg4;
#define CALLER_RESTORE_FltReg4 	FltReg4 = SAVE_Flt4;
#else
#define CALLER_SAVE_FltReg4    	/* nothing */
#define CALLER_RESTORE_FltReg4 	/* nothing */
#endif

#ifdef CALLER_SAVES_DblReg1
#define CALLER_SAVE_DblReg1    	SAVE_Dbl1 = DblReg1;
#define CALLER_RESTORE_DblReg1 	DblReg1 = SAVE_Dbl1;
#else
#define CALLER_SAVE_DblReg1    	/* nothing */
#define CALLER_RESTORE_DblReg1 	/* nothing */
#endif

#ifdef CALLER_SAVES_DblReg2
#define CALLER_SAVE_DblReg2    	SAVE_Dbl2 = DblReg2;
#define CALLER_RESTORE_DblReg2 	DblReg2 = SAVE_Dbl2;
#else
#define CALLER_SAVE_DblReg2    	/* nothing */
#define CALLER_RESTORE_DblReg2 	/* nothing */
#endif

#ifdef CALLER_SAVES_Tag
#define CALLER_SAVE_Tag	    	SAVE_Tag = TagReg;
#define CALLER_RESTORE_Tag  	TagReg = SAVE_Tag;
#else
#define CALLER_SAVE_Tag	    	/* nothing */
#define CALLER_RESTORE_Tag	/* nothing */
#endif

#ifdef CALLER_SAVES_Ret
#define CALLER_SAVE_Ret	    	SAVE_Ret = RetReg;
#define CALLER_RESTORE_Ret  	RetReg = SAVE_Ret;
#else
#define CALLER_SAVE_Ret	    	/* nothing */
#define CALLER_RESTORE_Ret	/* nothing */
#endif

#ifdef CALLER_SAVES_SpA
#define CALLER_SAVE_SpA	    	SAVE_SpA = SpA;
#define CALLER_RESTORE_SpA  	SpA = SAVE_SpA;
#else
#define CALLER_SAVE_SpA	    	/* nothing */
#define CALLER_RESTORE_SpA	/* nothing */
#endif

#ifdef CALLER_SAVES_SuA
#define CALLER_SAVE_SuA	    	SAVE_SuA = SuA;
#define CALLER_RESTORE_SuA  	SuA = SAVE_SuA;
#else
#define CALLER_SAVE_SuA	    	/* nothing */
#define CALLER_RESTORE_SuA	/* nothing */
#endif

#ifdef CALLER_SAVES_SpB
#define CALLER_SAVE_SpB	    	SAVE_SpB = SpB;
#define CALLER_RESTORE_SpB  	SpB = SAVE_SpB;
#else
#define CALLER_SAVE_SpB	    	/* nothing */
#define CALLER_RESTORE_SpB	/* nothing */
#endif

#ifdef CALLER_SAVES_SuB
#define CALLER_SAVE_SuB	    	SAVE_SuB = SuB;
#define CALLER_RESTORE_SuB  	SuB = SAVE_SuB;
#else
#define CALLER_SAVE_SuB	    	/* nothing */
#define CALLER_RESTORE_SuB	/* nothing */
#endif

#ifdef CALLER_SAVES_Hp
#define CALLER_SAVE_Hp	    	SAVE_Hp = Hp;
#define CALLER_RESTORE_Hp   	Hp = SAVE_Hp;
#else
#define CALLER_SAVE_Hp	    	/* nothing */
#define CALLER_RESTORE_Hp	/* nothing */
#endif

#ifdef CALLER_SAVES_HpLim
#define CALLER_SAVE_HpLim   	SAVE_HpLim = HpLim;
#define CALLER_RESTORE_HpLim	HpLim = SAVE_HpLim;
#else
#define CALLER_SAVE_HpLim   	/* nothing */
#define CALLER_RESTORE_HpLim   	/* nothing */
#endif

#ifdef CALLER_SAVES_Liveness
#define CALLER_SAVE_Liveness	SAVE_Liveness = LivenessReg;
#define CALLER_RESTORE_Liveness	LivenessReg = SAVE_Liveness;
#else
#define CALLER_SAVE_Liveness	/* nothing */
#define CALLER_RESTORE_Liveness	/* nothing */
#endif

#ifdef CALLER_SAVES_Base
#ifndef CONCURRENT
#define CALLER_SAVE_Base	/* nothing, ever (it holds a fixed value) */
#define CALLER_RESTORE_Base	BaseReg = &MainRegTable;
#else
#define CALLER_SAVE_Base	/* nothing */
#define CALLER_RESTORE_Base	BaseReg = CurrentRegTable;
#endif
#else
#define CALLER_SAVE_Base	/* nothing */
#define CALLER_RESTORE_Base	/* nothing */
#endif

#ifdef CALLER_SAVES_StdUpdRetVec
#define CALLER_RESTORE_StdUpdRetVec	StdUpdRetVecReg = vtbl_StdUpdFrame;
#else
#define CALLER_RESTORE_StdUpdRetVec	/* nothing */
#endif

#ifdef CALLER_SAVES_StkStub
#define CALLER_RESTORE_StkStub		StdUpdRetVecReg = STK_STUB_closure;
#else
#define CALLER_RESTORE_StkStub		/* nothing */
#endif

\end{code}

Concluding \tr{#endifs} and multi-slurp protection:

\begin{code}

#endif	/* SCAV_REG_MAP */
#endif	/* SCAN_REG_MAP */
#endif	/* MARK_REG_MAP */
#endif	/* NULL_REG_MAP */

#endif	/* STGREGS_H */
\end{code}