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;})
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;})
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=(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;})
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);})
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;})
114: # define MORE_VARS Inst 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;})
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 */
172: Cell engine(Inst *ip0, Cell *sp, char *fp)
173: {
174: /* VM registers (you may want to use gcc's "Explicit Reg Vars" here) */
175: Inst * ip;
176: Inst * 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++) {
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>