1 /* vm interpreter wrapper
2 
3   Copyright (C) 2001,2002,2003,2007 Free Software Foundation, Inc.
4 
5   This file is part of Gforth.
6 
7   Gforth is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License
9   as published by the Free Software Foundation, either version 3
10   of the License, or (at your option) any later version.
11 
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16 
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, see http://www.gnu.org/licenses/.
19 */
20 
21 #include "mini.h"
22 
23 #define USE_spTOS 1
24 
25 #ifdef USE_spTOS
26 #define IF_spTOS(x) x
27 #else
28 #define IF_spTOS(x)
29 #endif
30 
31 #ifdef VM_DEBUG
32 #define NAME(_x) if (vm_debug) {fprintf(vm_out, "%p: %-20s, ", ip-1, _x); fprintf(vm_out,"fp=%p, sp=%p", fp, sp);}
33 #else
34 #define NAME(_x)
35 #endif
36 
37 /* different threading schemes for different architectures; the sparse
38    numbering is there for historical reasons */
39 
40 /* here you select the threading scheme; I have only set this up for
41    386 and generic, because I don't know what preprocessor macros to
42    test for (Gforth uses config.guess instead).  Anyway, it's probably
43    best to build them all and select the fastest instead of hardwiring
44    a specific scheme for an architecture.  E.g., scheme 8 is fastest
45    for Gforth "make bench" on a 486, whereas scheme 5 is fastest for
46    "mini fib.mini" on an Athlon */
47 #ifndef THREADING_SCHEME
48 #define THREADING_SCHEME 5
49 #endif /* defined(THREADING_SCHEME) */
50 
51 #ifdef __GNUC__
52 #if THREADING_SCHEME==1
53 /* direct threading scheme 1: autoinc, long latency (HPPA, Sharc) */
54 #  define NEXT_P0	({cfa=*ip++;})
55 #  define IP		(ip-1)
56 #  define SET_IP(p)	({ip=(p); NEXT_P0;})
57 #  define NEXT_INST	(cfa)
58 #  define INC_IP(const_inc)	({cfa=IP[const_inc]; ip+=(const_inc);})
59 #  define DEF_CA
60 #  define NEXT_P1
61 #  define NEXT_P2	({goto *(cfa.inst);})
62 #endif
63 
64 #if THREADING_SCHEME==3
65 /* direct threading scheme 3: autoinc, low latency (68K) */
66 #  define NEXT_P0
67 #  define IP		(ip)
68 #  define SET_IP(p)	({ip=(p); NEXT_P0;})
69 #  define NEXT_INST	(*ip)
70 #  define INC_IP(const_inc)	({ip+=(const_inc);})
71 #  define DEF_CA
72 #  define NEXT_P1	({cfa=*ip++;})
73 #  define NEXT_P2	({goto *(cfa.inst);})
74 #endif
75 
76 #if THREADING_SCHEME==5
77 /* direct threading scheme 5: early fetching (Alpha, MIPS) */
78 #  define CFA_NEXT
79 #  define NEXT_P0	({cfa=*ip;})
80 #  define IP		(ip)
81 #  define SET_IP(p)	({ip=(Inst *)(p); NEXT_P0;})
82 #  define NEXT_INST	(cfa)
83 #  define INC_IP(const_inc)	({cfa=ip[const_inc]; ip+=(const_inc);})
84 #  define DEF_CA
85 #  define NEXT_P1	(ip++)
86 #  define NEXT_P2	({goto *(cfa.inst);})
87 #endif
88 
89 #if THREADING_SCHEME==8
90 /* direct threading scheme 8: i386 hack */
91 #  define NEXT_P0
92 #  define IP		(ip)
93 #  define SET_IP(p)	({ip=(p); NEXT_P0;})
94 #  define NEXT_INST	(*IP)
95 #  define INC_IP(const_inc)	({ ip+=(const_inc);})
96 #  define DEF_CA
97 #  define NEXT_P1	(ip++)
98 #  define NEXT_P2	({goto *((*(ip-1)).inst);})
99 #endif
100 
101 #if THREADING_SCHEME==9
102 /* direct threading scheme 9: prefetching (for PowerPC) */
103 /* note that the "cfa=next_cfa;" occurs only in NEXT_P1, because this
104    works out better with the capabilities of gcc to introduce and
105    schedule the mtctr instruction. */
106 #  define NEXT_P0
107 #  define IP		ip
108 #  define SET_IP(p)	({ip=(p); next_cfa=*ip; NEXT_P0;})
109 #  define NEXT_INST	(next_cfa)
110 #  define INC_IP(const_inc)	({next_cfa=IP[const_inc]; ip+=(const_inc);})
111 #  define DEF_CA
112 #  define NEXT_P1	({cfa=next_cfa; ip++; next_cfa=*ip;})
113 #  define NEXT_P2	({goto *(cfa.inst);})
114 #  define MORE_VARS	Cell next_cfa;
115 #endif
116 
117 #if THREADING_SCHEME==10
118 /* direct threading scheme 10: plain (no attempt at scheduling) */
119 #  define NEXT_P0
120 #  define IP		(ip)
121 #  define SET_IP(p)	({ip=(p); NEXT_P0;})
122 #  define NEXT_INST	(*ip)
123 #  define INC_IP(const_inc)	({ip+=(const_inc);})
124 #  define DEF_CA
125 #  define NEXT_P1
126 #  define NEXT_P2	({cfa=*ip++; goto *(cfa.inst);})
127 #endif
128 
129 
130 #define NEXT ({DEF_CA NEXT_P1; NEXT_P2;})
131 #define IPTOS ((NEXT_INST))
132 
133 #define INST_ADDR(name) (Label)&&I_##name
134 #define LABEL(name) I_##name:
135 #else /* !defined(__GNUC__) */
136 /* use switch dispatch */
137 #define DEF_CA
138 #define NEXT_P0
139 #define NEXT_P1
140 #define NEXT_P2 goto next_inst;
141 #define SET_IP(p)	(ip=(p))
142 #define IP              ip
143 #define NEXT_INST	(*ip)
144 #define INC_IP(const_inc)	(ip+=(const_inc))
145 #define IPTOS NEXT_INST
146 #define INST_ADDR(name) I_##name
147 #define LABEL(name) case I_##name:
148 
149 #endif /* !defined(__GNUC__) */
150 
151 #define LABEL2(x)
152 
153 #ifdef VM_PROFILING
154 #define SUPER_END  vm_count_block(IP)
155 #else
156 #define SUPER_END
157 #endif
158 
159 #ifndef __GNUC__
160 enum {
161 #include "mini-labels.i"
162 };
163 #endif
164 
165 #if defined(__GNUC__) && ((__GNUC__==2 && defined(__GNUC_MINOR__) && __GNUC_MINOR__>=7)||(__GNUC__>2))
166 #define MAYBE_UNUSED __attribute__((unused))
167 #else
168 #define MAYBE_UNUSED
169 #endif
170 
171 /* the return type can be anything you want it to */
engine(Cell * ip0,Cell * sp,char * fp)172 long engine(Cell *ip0, Cell *sp, char *fp)
173 {
174   /* VM registers (you may want to use gcc's "Explicit Reg Vars" here) */
175   Cell * ip;
176   Cell cfa;
177 #ifdef USE_spTOS
178   Cell   spTOS;
179 #else
180 #define spTOS (sp[0])
181 #endif
182   static Label   labels[] = {
183 #include "mini-labels.i"
184   };
185 #ifdef MORE_VARS
186   MORE_VARS
187 #endif
188 
189   if (vm_debug)
190       fprintf(vm_out,"entering engine(%p,%p,%p)\n",ip0,sp,fp);
191   if (ip0 == NULL) {
192     vm_prim = labels;
193     return 0;
194   }
195 
196   /* I don't have a clue where these things come from,
197      but I've put them in macros.h for the moment */
198   IF_spTOS(spTOS = sp[0]);
199 
200   SET_IP(ip0);
201   SUPER_END;  /* count the BB starting at ip0 */
202 
203 #ifdef __GNUC__
204   NEXT;
205 #include "mini-vm.i"
206 #else
207  next_inst:
208   switch((*ip++).inst) {
209 #include "mini-vm.i"
210   default:
211     fprintf(stderr,"unknown instruction %d at %p\n", ip[-1], ip-1);
212     exit(1);
213   }
214 #endif
215 }
216