File: codegen.h

package info (click to toggle)
psyco-doc 1.6-1
  • links: PTS
  • area: contrib
  • in suites: lenny
  • size: 1,832 kB
  • ctags: 3,236
  • sloc: ansic: 23,895; python: 5,646; perl: 1,309; makefile: 153
file content (351 lines) | stat: -rw-r--r-- 14,517 bytes parent folder | download | duplicates (6)
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
 /***************************************************************/
/***            Processor-specific code generation             ***/
 /***************************************************************/

#ifndef _CODEGEN_H
#define _CODEGEN_H


#include "vcompiler.h"
#include <iencoding.h>

#if SIZEOF_LONG == 4
# define SIZE_OF_LONG_BITS   2
#else
# error "-----------------------------------------------------"
# error "Sorry, non-32-bit platforms are not supported at all."
# error "You may try with a Python compiled in 32-bit         "
# error "compatibility mode.  Note that Psyco will probably   "
# error "never support non-32-bit platforms, as it is no      "
# error "longer actively developed.  Instead, the PyPy group  "
# error "plans to replace it with a more flexible and easily  "
# error "retargettable Psyco-for-PyPy during the year 2006.   "
# error "See http://codespeak.net/pypy/                       "
# error "-----------------------------------------------------"
#endif

#if SIZEOF_LONG != SIZEOF_VOID_P
# error "Sorry, your platform is not supported at all."
# error "Psyco currently requires sizeof(long)==sizeof(void*)."
#endif

#define INITIAL_STACK_DEPTH  4 /* anything >0 and a multiple of 4 */


/***************************************************************/
 /*** Condition Codes (a.k.a. the processor 'flags' register) ***/

/* return a new vinfo_t* meaning `in the processor flags, true if <cc>',
   as an integer 0 or 1.  The source of the vinfo_t* is compile-time
   if cc is CC_ALWAYS_TRUE/FALSE, and virtual-time otherwise. */
EXTERNFN vinfo_t* psyco_vinfo_condition(PsycoObject* po, condition_code_t cc);
EXTERNFN VirtualTimeSource psyco_source_condition(condition_code_t cc);

/* if 'source' comes from psyco_vinfo_condition(), return its <cc>;
   otherwise return CC_ALWAYS_FALSE. */
#if HAVE_CCREG
EXTERNFN condition_code_t psyco_vsource_cc(Source source);
EXTERNFN void psyco_resolved_cc(PsycoObject* po, condition_code_t cc_known_true);
#else
# define psyco_vsource_cc(src)  CC_ALWAYS_FALSE
#endif


/***************************************************************/
 /*** Read/write memory                                       ***/

/* access the data word at address 'nv_ptr + offset + (rt_vindex<<size2)'.
   'nv_ptr' must be a non-virtual source.
   'rt_vindex' must be a run-time source or NULL.
   '1<<size2' also specifies the size of the data word to access.
   '1<<size2' must be 1, 2, 4 or 8 (in the latter case, only the first 4 bytes
     are accessed anyway).
   'nonsigned' selects between zero- and sign-extension
     if '1<<size2' is 1 or 2. */
EXTERNFN vinfo_t* psyco_memory_read(PsycoObject* po, vinfo_t* nv_ptr,
                                    long offset, vinfo_t* rt_vindex,
                                    int size2, bool nonsigned);
EXTERNFN bool psyco_memory_write(PsycoObject* po, vinfo_t* nv_ptr,
                                 long offset, vinfo_t* rt_vindex,
                                 int size2, vinfo_t* value);


#if 0
/* XXX to do: references from the code buffers. This is tricky because
   we can have quite indirect references, or references to a subobject of
   a Python object, or to a field only of a Python object, etc... */
PSY_INLINE long reference_from_code(PsycoObject* po, CompileTimeSource source)
{
	--- DISABLED ---
	source_known_t* sk = CompileTime_Get(source);
	if ((sk->refcount1_flags & SkFlagPyObj) != 0) {
		/* XXX we get a reference from the code.
		   Implement freeing such references
		   together with code buffers. */
		sk_incref(sk);
	}
	return sk->value;
}
#endif


/*****************************************************************/
 /***   Calling C functions                                     ***/

/* A generic way of emitting the call to a C function.
   For maximal performance you can also directly use the macros
   CALL_C_FUNCTION()&co. in encoding.h.

   'arguments' is a string describing the following arguments
   of psyco_generic_call(). Each argument to the C function to call
   comes from a 'vinfo_t*' structure, excepted when it is known to be
   compile-time, in which case a 'long' or 'PyObject*' can be passed
   instead. In 'arguments' the characters are interpreted as follows:

      l      an immediate 'long' or 'PyObject*' value
      v      a 'vinfo_t*' value
      r      a run-time 'vinfo_t*' value passed as a reference
      a      a 'vinfo_array_t*' used by the C function as output buffer
      A      same as 'a', but the C function creates new references

   'r' means that the C function wants to get a reference to a
   single-word value (typically it is an output argument). The
   run-time value is pushed in the stack if it is just in a
   register. Incompatible with CfPure.

   'a' means that the C function gets a pointer to a buffer capable of
   containing as many words as specified by the array count.
   psyco_generic_call() fills the array with run-time vinfo_ts
   representing the output values.
*/
EXTERNFN vinfo_t* psyco_generic_call(PsycoObject* po, void* c_function,
                                     int flags, const char* arguments, ...);

/* if the C function has no side effect it can be called at compile-time
   if all its arguments are compile-time. Use CfPure in this case. */
#define CfPure           0x10

/* if the C function returns a long or a PyObject* but not a new reference */
#define CfReturnNormal   0x00   /* default */

/* if the C function returns a new reference */
#define CfReturnRef      0x01

/* if the C function does not return anything
   or if you are not interested in getting the result in a vinfo_t.
   psyco_generic_call() returns anything non-NULL (unless there is an error)
   in this case. */
#define CfNoReturnValue  0x03

#define CfReturnMask     0x0F
/* See also the Python-specific flags CfPyErrXxx defined in pycheader.h. */


/* To emit the call to other code blocks emitted by Psyco. 'argsources' gives
   the run-time sources for the arguments, as specified by
   psyco_build_frame(). */
EXTERNFN vinfo_t* psyco_call_psyco(PsycoObject* po, CodeBufferObject* codebuf,
				   Source argsources[], int argcount,
				   struct stack_frame_info_s* finfo);

PSY_INLINE int get_arguments_count(vinfo_array_t* vlocals) {
	int retpos = getstack(vlocals->items[INDEX_LOC_CONTINUATION]->source);
	extra_assert(retpos != RunTime_StackNone);
	return (retpos-(INITIAL_STACK_DEPTH+sizeof(long))) / sizeof(long);
}

/* Emit the code to mark the presence of an inlined frame */
EXTERNFN void psyco_inline_enter(PsycoObject* po);
EXTERNFN void psyco_inline_exit (PsycoObject* po);


/*****************************************************************/
 /***   Emit common instructions                                ***/

/* Returns a condition code for: "'vi' is not null". Warning, when a
   function returns a condition code it must be used immediately, before
   there is any chance for new code to be emitted. If you are unsure, use
   psyco_vinfo_condition() to turn the condition code into a 0 or 1 integer. */
EXTERNFN condition_code_t integer_non_null(PsycoObject* po, vinfo_t* vi);

/* Same as above, but consumes the reference on 'vi'. Also checks if
   'vi==NULL' and returns CC_ERROR in this case. */
EXTERNFN condition_code_t integer_NON_NULL(PsycoObject* po, vinfo_t* vi);

/* Instructions with an 'ovf' parameter will check for overflow
   if 'ovf' is true. They return NULL if an overflow is detected. */
EXTERNFN
vinfo_t* integer_add  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2, bool ovf);
EXTERNFN   /* 'unsafe': optimize by silently assuming no overflow is possible */
vinfo_t* integer_add_i(PsycoObject* po, vinfo_t* v1, long value2, bool unsafe);
EXTERNFN
vinfo_t* integer_sub  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2, bool ovf);
/*EXTERNFN XXX implement me
  vinfo_t* integer_sub_i(PsycoObject* po, vinfo_t* v1, long value2);*/
EXTERNFN
vinfo_t* integer_mul  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2, bool ovf);
EXTERNFN
vinfo_t* integer_mul_i(PsycoObject* po, vinfo_t* v1, long value2);
EXTERNFN
vinfo_t* integer_or   (PsycoObject* po, vinfo_t* v1, vinfo_t* v2);
EXTERNFN
vinfo_t* integer_xor  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2);
EXTERNFN
vinfo_t* integer_and  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2);
/*EXTERNFN
  vinfo_t* integer_and_i(PsycoObject* po, vinfo_t* v1, long value2);*/
EXTERNFN
vinfo_t* integer_lshift  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2);
EXTERNFN              /* signed */
vinfo_t* integer_rshift  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2);
/*EXTERNFN              unsigned
  vinfo_t* integer_urshift  (PsycoObject* po, vinfo_t* v1, vinfo_t* v2);*/
EXTERNFN
vinfo_t* integer_lshift_i(PsycoObject* po, vinfo_t* v1, long counter);
EXTERNFN              /* signed */
vinfo_t* integer_rshift_i(PsycoObject* po, vinfo_t* v1, long counter);
EXTERNFN              /* unsigned */
vinfo_t* integer_urshift_i(PsycoObject* po, vinfo_t* v1, long counter);
EXTERNFN
vinfo_t* integer_inv  (PsycoObject* po, vinfo_t* v1);
EXTERNFN
vinfo_t* integer_neg  (PsycoObject* po, vinfo_t* v1, bool ovf);
EXTERNFN
vinfo_t* integer_abs  (PsycoObject* po, vinfo_t* v1, bool ovf);
/* Comparison: 'py_op' is one of Python's rich comparison numbers
   Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE
   optionally together with COMPARE_UNSIGNED, CHEAT_MAXINT. */
EXTERNFN condition_code_t integer_cmp  (PsycoObject* po, vinfo_t* v1,
					vinfo_t* v2, int py_op);
EXTERNFN condition_code_t integer_cmp_i(PsycoObject* po, vinfo_t* v1,
					long value2, int py_op);
#define COMPARE_UNSIGNED  8
#define CHEAT_MAXINT     16  /* assume only a constant can be exactly
                                LONG_MIN or LONG_MAX */
#define COMPARE_BASE_MASK 7
#define COMPARE_OP_MASK  15

/* Return one of two constants, depending on the condition code */
EXTERNFN vinfo_t* integer_conditional(PsycoObject* po, condition_code_t cc,
                                      long immed_true, long immed_false);

/* make a run-time copy of a vinfo_t */
EXTERNFN vinfo_t* make_runtime_copy(PsycoObject* po, vinfo_t* v);

PSY_INLINE int intlog2(long value) {
  int counter = 0;
  while ((1<<counter) < value)
    counter++;
  return counter;
}


/*****************************************************************/
 /***   code termination                                        ***/

/* write a function header reserving 'nframelocal' machine words for
   local storage. These are put in an array under LOC_CONTINUATION as
   run-time values. Do not use this with nframelocal==0; no header is
   needed (so far) in this case. */
EXTERNFN void psyco_emit_header(PsycoObject* po, int nframelocal);

/* write a return, clearing the stack as necessary, and releases 'po'.
   'retval' may not be virtual-time in the current implementation. */
EXTERNFN code_t* psyco_finish_return(PsycoObject* po, Source retval);

/* write codes that calls the C function 'fn' and jumps to its
   return value.
   Set 'restore' to 1 to save and restore all used registers across call,
   or 0 to just unload the used registers into the stack.
   This function returns a pointer to the end of the jumping code, where
   you can store closure data for 'fn'.
   The arguments that will be passed to 'fn' are:
   1) the same pointer to the closure data
   2) the run-time value described by 'extraarg' if != SOURCE_DUMMY. */
EXTERNFN
void* psyco_call_code_builder(PsycoObject* po, void* fn, int restore,
                              RunTimeSource extraarg);

#if 0   /* disabled */
/* emergency code for out-of-memory conditions in which do not
   have a code buffer available for psyco_finish_err_xxx().
   A temporary buffer of the size EMERGENCY_PROXY_SIZE is enough. */
#define EMERGENCY_PROXY_SIZE    11
code_t* psyco_emergency_jump(PsycoObject* po, code_t* code);
#endif


/*****************************************************************/
 /***   run-time switches                                       ***/

#define USE_RUNTIME_SWITCHES  0    /* DISABLED, no longer maintained */

typedef struct c_promotion_s {
  source_virtual_t header;
  int pflags;
} c_promotion_t;

#define PFlagPyObj		1
#define PFlagMegamorphic	2


#if USE_RUNTIME_SWITCHES

typedef struct fixed_switch_s {  /* private structure */
  int switchcodesize;   /* size of 'switchcode' */
  code_t* switchcode;
  int count;
  struct fxcase_s* fxc;
  long* fixtargets;
  long zero;            /* for 'array' pointers from vinfo_t structures */
  struct c_promotion_s fixed_promotion; /* pseudo-exception meaning 'fix me' */
} fixed_switch_t;

/* initialization of a fixed_switch_t structure */
EXTERNFN int psyco_build_run_time_switch(fixed_switch_t* rts, long kflags,
                                         long values[], int count);

/* Look for a (known) value in a prepared switch.
   Return -1 if not found. */
EXTERNFN int psyco_switch_lookup(fixed_switch_t* rts, long value);

/* Write the code that does a 'switch' on the prepared 'values'.
   The register 'reg' contains the value to switch on. All jump targets
   are initially at the end of the written code; see
   psyco_fix_switch_target(). */
EXTERNFN code_t* psyco_write_run_time_switch(fixed_switch_t* rts,
                                             code_t* code, reg_t reg);

/* Fix the target corresponding to the given case ('item' is a value
   returned by psyco_switch_lookup()). 'code' is the *end* of the
   switch code, as returned by psyco_write_run_time_switch(). */
EXTERNFN void psyco_fix_switch_case(fixed_switch_t* rts, code_t* code,
                                    int item, code_t* newtarget);

/* is the given run-time vinfo_t known to be none of the values
   listed in rts? */
PSY_INLINE bool known_to_be_default(vinfo_t* vi, fixed_switch_t* rts) {
	return vi->array == NullArrayAt(rts->zero);
}

#endif  /* USE_RUNTIME_SWITCHES */


/* The pseudo-exceptions meaning 'promote me' but against no particular
   fixed_switch_t. The second one has the SkFlagPyObj flag. */
EXTERNVAR c_promotion_t psyco_nonfixed_promotion;
EXTERNVAR c_promotion_t psyco_nonfixed_pyobj_promotion;

/* The same, but detecting megamorphic sites, where many different run-time
   values keep showing up.  Promotion stop after MEGAMORPHIC_MAX different
   values. */
/*EXTERNVAR c_promotion_t psyco_nonfixed_promotion_mega;*/
EXTERNVAR c_promotion_t psyco_nonfixed_pyobj_promotion_mega;

#define MEGAMORPHIC_MAX    5

/* Check if the given virtual source is a promotion exception */
EXTERNFN bool psyco_vsource_is_promotion(VirtualTimeSource source);


#endif /* _CODEGEN_H */