StgCRun.c 15.8 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2
 * $Id: StgCRun.c,v 1.31 2002/03/26 10:35:20 simonmar Exp $
3
 *
4
 * (c) The GHC Team, 1998-2000
5
 *
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 * STG-to-C glue.
 *
 * To run an STG function from C land, call
 *
 *		rv = StgRun(f,BaseReg);
 *
 * where "f" is the STG function to call, and BaseReg is the address of the
 * RegTable for this run (we might have separate RegTables if we're running
 * multiple threads on an SMP machine).
 *
 * In the end, "f" must JMP to StgReturn (defined below),
 * passing the return-value "rv" in R1,
 * to return to the caller of StgRun returning "rv" in
 * the whatever way C returns a value.
 *
 * NOTE: StgRun/StgReturn do *NOT* load or store Hp or any
ken's avatar
ken committed
22
 * other registers (other than saving the C callee-saves
23
24
 * registers).  Instead, the called function "f" must do that
 * in STG land.
ken's avatar
ken committed
25
 *
26
27
28
29
30
31
 * GCC will have assumed that pushing/popping of C-stack frames is
 * going on when it generated its code, and used stack space
 * accordingly.  However, we actually {\em post-process away} all
 * such stack-framery (see \tr{ghc/driver/ghc-asm.lprl}). Things will
 * be OK however, if we initially make sure there are
 * @RESERVED_C_STACK_BYTES@ on the C-stack to begin with, for local
ken's avatar
ken committed
32
 * variables.
33
34
35
 *
 * -------------------------------------------------------------------------- */

36
37
#include "PosixSource.h"

ken's avatar
ken committed
38
39
40
41
42
43
44
45
46
47
48

/*
 * We define the following (unused) global register variables, because for
 * some reason gcc generates sub-optimal code for StgRun() on the Alpha
 * (unnecessarily saving extra registers on the stack) if we don't.
 *
 * Why do it at the top of this file, rather than near StgRun() below?  Because
 * gcc doesn't let us define global register variables after any function
 * definition has been read.  Any point after #include "Stg.h" would be too
 * late.
 *
ken's avatar
ken committed
49
50
51
 * We define alpha_EXTRA_CAREFUL here to save $s6, $f8 and $f9 -- registers
 * that we don't use but which are callee-save registers.  The __divq() routine
 * in libc.a clobbers $s6.
ken's avatar
ken committed
52
53
54
 */
#include "config.h"
#ifdef alpha_TARGET_ARCH
ken's avatar
ken committed
55
#define alpha_EXTRA_CAREFUL
ken's avatar
ken committed
56
57
58
59
60
61
62
63
register long   fake_ra __asm__("$26");
#ifdef alpha_EXTRA_CAREFUL
register long   fake_s6 __asm__("$15");
register double fake_f8 __asm__("$f8");
register double fake_f9 __asm__("$f9");
#endif
#endif

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* include Stg.h first because we want real machine regs in here: we
 * have to get the value of R1 back from Stg land to C land intact.
 */
#include "Stg.h"
#include "Rts.h"
#include "StgRun.h"

#ifdef DEBUG
#include "RtsFlags.h"
#include "RtsUtils.h"
#include "Printer.h"
#endif

#ifdef USE_MINIINTERPRETER

/* -----------------------------------------------------------------------------
   any architecture (using miniinterpreter)
   -------------------------------------------------------------------------- */
ken's avatar
ken committed
82

sof's avatar
sof committed
83
extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)
84
{
85
86
87
   while (f) {
      IF_DEBUG(evaluator,
	       fprintf(stderr,"Jumping to ");
sof's avatar
sof committed
88
	       printPtr((P_)f); fflush(stdout);
89
	       fprintf(stderr,"\n");
90
91
92
93
	      );
      f = (StgFunPtr) (f)();
   }
   return (StgThreadReturnCode)R1.i;
94
95
96
97
}

EXTFUN(StgReturn)
{
98
   return 0;
99
100
101
102
103
104
105
106
107
108
}

#else /* !USE_MINIINTERPRETER */

#ifdef LEADING_UNDERSCORE
#define STG_RETURN "_StgReturn"
#else
#define STG_RETURN "StgReturn"
#endif

109
110
111
/* -----------------------------------------------------------------------------
   x86 architecture
   -------------------------------------------------------------------------- */
ken's avatar
ken committed
112

113
114
115
116
117
#ifdef i386_TARGET_ARCH

StgThreadReturnCode
StgRun(StgFunPtr f, StgRegTable *basereg) {

118
    unsigned char space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ];
119
120
121
    StgThreadReturnCode r;

    __asm__ volatile (
ken's avatar
ken committed
122
	/*
123
124
125
	 * save callee-saves registers on behalf of the STG code.
	 */
	"movl %%esp, %%eax\n\t"
126
	"addl %4, %%eax\n\t"
127
128
129
130
131
132
133
        "movl %%ebx,0(%%eax)\n\t"
        "movl %%esi,4(%%eax)\n\t"
        "movl %%edi,8(%%eax)\n\t"
        "movl %%ebp,12(%%eax)\n\t"
	/*
	 * Set BaseReg
	 */
134
	"movl %3,%%ebx\n\t"
135
	/*
136
	 * grab the function argument from the stack, and jump to it.
137
	 */
138
        "movl %2,%%eax\n\t"
139
140
141
142
        "jmp *%%eax\n\t"

	".global " STG_RETURN "\n"
       	STG_RETURN ":\n\t"
143
144
145

	"movl %%esi, %%eax\n\t"   /* Return value in R1  */

146
147
148
149
	/*
	 * restore callee-saves registers.  (Don't stomp on %%eax!)
	 */
	"movl %%esp, %%edx\n\t"
150
	"addl %4, %%edx\n\t"
151
152
153
154
155
        "movl 0(%%edx),%%ebx\n\t"	/* restore the registers saved above */
        "movl 4(%%edx),%%esi\n\t"
        "movl 8(%%edx),%%edi\n\t"
        "movl 12(%%edx),%%ebp\n\t"

156
157
      : "=&a" (r), "=m" (space)
      : "m" (f), "m" (basereg), "i" (RESERVED_C_STACK_BYTES)
158
159
160
161
162
163
164
165
      : "edx" /* stomps on %edx */
    );

    return r;
}

#endif

166
/* -----------------------------------------------------------------------------
167
168
   Sparc architecture

ken's avatar
ken committed
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
   OLD COMMENT from GHC-3.02:

   We want tailjumps to be calls, because `call xxx' is the only Sparc
   branch that allows an arbitrary label as a target.  (Gcc's ``goto
   *target'' construct ends up loading the label into a register and
   then jumping, at the cost of two extra instructions for the 32-bit
   load.)

   When entering the threaded world, we stash our return address in a
   known location so that \tr{%i7} is available as an extra
   callee-saves register.  Of course, we have to restore this when
   coming out of the threaded world.

   I hate this god-forsaken architecture.  Since the top of the
   reserved stack space is used for globals and the bottom is reserved
   for outgoing arguments, we have to stick our return address
   somewhere in the middle.  Currently, I'm allowing 100 extra
   outgoing arguments beyond the first 6.  --JSM

   Updated info (GHC 4.06): we don't appear to use %i7 any more, so
   I'm not sure whether we still need to save it.  Incedentally, what
   does the last paragraph above mean when it says "the top of the
   stack is used for globals"?  What globals?  --SDM

194
   Updated info (GHC 4.08.2): not saving %i7 any more (see below).
195
   -------------------------------------------------------------------------- */
ken's avatar
ken committed
196

197
198
199
#ifdef sparc_TARGET_ARCH

StgThreadReturnCode
200
StgRun(StgFunPtr f, StgRegTable *basereg) {
201

202
203
204
205
206
    unsigned char space[RESERVED_C_STACK_BYTES];
#if 0
    register void *i7 __asm__("%i7");
    ((void **)(space))[100] = i7;
#endif
207
    f();
208
    __asm__ volatile (
ken's avatar
ken committed
209
	    ".align 4\n"
210
            ".global " STG_RETURN "\n"
ken's avatar
ken committed
211
       	    STG_RETURN ":"
212
213
214
215
216
217
218
219
220
221
222
	    : : : "l0","l1","l2","l3","l4","l5","l6","l7");
    /* we tell the C compiler that l0-l7 are clobbered on return to
     * StgReturn, otherwise it tries to use these to save eg. the
     * address of space[100] across the call.  The correct thing
     * to do would be to save all the callee-saves regs, but we
     * can't be bothered to do that.
     *
     * The code that gcc generates for this little fragment is now
     * terrible.  We could do much better by coding it directly in
     * assembler.
     */
223
#if 0
224
225
226
227
228
    /* updated 4.08.2: we don't save %i7 in the middle of the reserved
     * space any more, since gcc tries to save its address across the
     * call to f(), this gets clobbered in STG land and we end up
     * dereferencing a bogus pointer in StgReturn.
     */
ken's avatar
ken committed
229
    __asm__ volatile ("ld %1,%0"
230
		      : "=r" (i7) : "m" (((void **)(space))[100]));
231
#endif
232
233
234
235
236
237
238
    return (StgThreadReturnCode)R1.i;
}

#endif

/* -----------------------------------------------------------------------------
   alpha architecture
ken's avatar
ken committed
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

   "The stack pointer (SP) must at all times denote an address that has octaword
    alignment. (This restriction has the side effect that the in-memory portion
    of the argument list, if any, will start on an octaword boundary.) Note that
    the stack grows toward lower addresses. During a procedure invocation, SP
    can never be set to a value that is higher than the value of SP at entry to
    that procedure invocation.

   "The contents of the stack, located above the portion of the argument list
    (if any) that is passed in memory, belong to the calling procedure. Because
    they are part of the calling procedure, they should not be read or written
    by the called procedure, except as specified by indirect arguments or
    language-controlled up-level references.

   "The SP value might be used by the hardware when raising exceptions and
    asynchronous interrupts. It must be assumed that the contents of the stack
    below the current SP value and within the stack for the current thread are
    continually and unpredictably modified, as specified in the _Alpha
    Architecture Reference Manual_, and as a result of asynchronous software
    actions."

ken's avatar
ken committed
260
   -- Compaq Computer Corporation, Houston. Tru64 UNIX Calling Standard for
ken's avatar
ken committed
261
262
      Alpha Systems, 5.1 edition, August 2000, section 3.2.1.  http://www.
      tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_PDF/ARH9MBTE.PDF
263
264
265
266
267
   -------------------------------------------------------------------------- */

#ifdef alpha_TARGET_ARCH

StgThreadReturnCode
ken's avatar
ken committed
268
StgRun(StgFunPtr f, StgRegTable *basereg)
269
{
ken's avatar
ken committed
270
271
272
273
274
275
276
277
278
279
280
    register long   real_ra __asm__("$26"); volatile long   save_ra;

    register long   real_s0 __asm__("$9" ); volatile long   save_s0;
    register long   real_s1 __asm__("$10"); volatile long   save_s1;
    register long   real_s2 __asm__("$11"); volatile long   save_s2;
    register long   real_s3 __asm__("$12"); volatile long   save_s3;
    register long   real_s4 __asm__("$13"); volatile long   save_s4;
    register long   real_s5 __asm__("$14"); volatile long   save_s5;
#ifdef alpha_EXTRA_CAREFUL
    register long   real_s6 __asm__("$15"); volatile long   save_s6;
#endif
ken's avatar
ken committed
281

ken's avatar
ken committed
282
283
284
285
286
287
288
289
290
291
292
293
294
    register double real_f2 __asm__("$f2"); volatile double save_f2;
    register double real_f3 __asm__("$f3"); volatile double save_f3;
    register double real_f4 __asm__("$f4"); volatile double save_f4;
    register double real_f5 __asm__("$f5"); volatile double save_f5;
    register double real_f6 __asm__("$f6"); volatile double save_f6;
    register double real_f7 __asm__("$f7"); volatile double save_f7;
#ifdef alpha_EXTRA_CAREFUL
    register double real_f8 __asm__("$f8"); volatile double save_f8;
    register double real_f9 __asm__("$f9"); volatile double save_f9;
#endif

    register StgFunPtr real_pv __asm__("$27");

295
296
    StgThreadReturnCode ret;

ken's avatar
ken committed
297
    save_ra = real_ra;
298

ken's avatar
ken committed
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
    save_s0 = real_s0;
    save_s1 = real_s1;
    save_s2 = real_s2;
    save_s3 = real_s3;
    save_s4 = real_s4;
    save_s5 = real_s5;
#ifdef alpha_EXTRA_CAREFUL
    save_s6 = real_s6;
#endif

    save_f2 = real_f2;
    save_f3 = real_f3;
    save_f4 = real_f4;
    save_f5 = real_f5;
    save_f6 = real_f6;
    save_f7 = real_f7;
#ifdef alpha_EXTRA_CAREFUL
    save_f8 = real_f8;
    save_f9 = real_f9;
#endif

    real_pv = f;

    __asm__ volatile(	"lda $30,-%0($30)"	"\n"
		"\t"	"jmp ($27)"		"\n"
		"\t"	".align 3"		"\n"
		".globl " STG_RETURN		"\n"
		STG_RETURN ":"			"\n"
		"\t"	"lda $30,%0($30)"	"\n"
		: : "K" (RESERVED_C_STACK_BYTES));

    ret = real_s5;

    real_s0 = save_s0;
    real_s1 = save_s1;
    real_s2 = save_s2;
    real_s3 = save_s3;
    real_s4 = save_s4;
    real_s5 = save_s5;
#ifdef alpha_EXTRA_CAREFUL
    real_s6 = save_s6;
#endif

    real_f2 = save_f2;
    real_f3 = save_f3;
    real_f4 = save_f4;
    real_f5 = save_f5;
    real_f6 = save_f6;
    real_f7 = save_f7;
#ifdef alpha_EXTRA_CAREFUL
    real_f8 = save_f8;
    real_f9 = save_f9;
#endif
352

ken's avatar
ken committed
353
    real_ra = save_ra;
354

355
    return ret;
356
357
}

358
#endif /* alpha_TARGET_ARCH */
359

360
361
362
363
364
365
366
/* -----------------------------------------------------------------------------
   HP-PA architecture
   -------------------------------------------------------------------------- */

#ifdef hppa1_1_TARGET_ARCH

StgThreadReturnCode
ken's avatar
ken committed
367
StgRun(StgFunPtr f, StgRegTable *basereg)
368
369
{
    StgChar space[RESERVED_C_STACK_BYTES+16*sizeof(long)+10*sizeof(double)];
370
    StgThreadReturnCode ret;
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
    __asm__ volatile ("ldo %0(%%r30),%%r19\n"
		      "\tstw %%r3, 0(0,%%r19)\n"
                      "\tstw %%r4, 4(0,%%r19)\n"
                      "\tstw %%r5, 8(0,%%r19)\n"
                      "\tstw %%r6,12(0,%%r19)\n"
                      "\tstw %%r7,16(0,%%r19)\n"
                      "\tstw %%r8,20(0,%%r19)\n"
                      "\tstw %%r9,24(0,%%r19)\n"
		      "\tstw %%r10,28(0,%%r19)\n"
                      "\tstw %%r11,32(0,%%r19)\n"
                      "\tstw %%r12,36(0,%%r19)\n"
                      "\tstw %%r13,40(0,%%r19)\n"
                      "\tstw %%r14,44(0,%%r19)\n"
                      "\tstw %%r15,48(0,%%r19)\n"
                      "\tstw %%r16,52(0,%%r19)\n"
                      "\tstw %%r17,56(0,%%r19)\n"
                      "\tstw %%r18,60(0,%%r19)\n"
		      "\tldo 80(%%r19),%%r19\n"
		      "\tfstds %%fr12,-16(0,%%r19)\n"
		      "\tfstds %%fr13, -8(0,%%r19)\n"
		      "\tfstds %%fr14,  0(0,%%r19)\n"
		      "\tfstds %%fr15,  8(0,%%r19)\n"
		      "\tldo 32(%%r19),%%r19\n"
		      "\tfstds %%fr16,-16(0,%%r19)\n"
		      "\tfstds %%fr17, -8(0,%%r19)\n"
		      "\tfstds %%fr18,  0(0,%%r19)\n"
		      "\tfstds %%fr19,  8(0,%%r19)\n"
		      "\tldo 32(%%r19),%%r19\n"
		      "\tfstds %%fr20,-16(0,%%r19)\n"
		      "\tfstds %%fr21, -8(0,%%r19)\n" : :
                      "n" (-(116 * sizeof(long) + 10 * sizeof(double))) : "%r19"
		      );

    f();

    __asm__ volatile (".align 4\n"
               	      "\t.EXPORT " STG_RETURN ",CODE\n"
		      "\t.EXPORT " STG_RETURN ",ENTRY,PRIV_LEV=3\n"
                      STG_RETURN "\n"
                      /* "\tldo %0(%%r3),%%r19\n" */
412
413
                      "\tldo %1(%%r30),%%r19\n"
                      "\tcopy %%r11, %0\n"  /* save R1 */
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
		      "\tldw  0(0,%%r19),%%r3\n"
                      "\tldw  4(0,%%r19),%%r4\n"
                      "\tldw  8(0,%%r19),%%r5\n"
                      "\tldw 12(0,%%r19),%%r6\n"
                      "\tldw 16(0,%%r19),%%r7\n"
                      "\tldw 20(0,%%r19),%%r8\n"
                      "\tldw 24(0,%%r19),%%r9\n"
		      "\tldw 28(0,%%r19),%%r10\n"
                      "\tldw 32(0,%%r19),%%r11\n"
                      "\tldw 36(0,%%r19),%%r12\n"
                      "\tldw 40(0,%%r19),%%r13\n"
                      "\tldw 44(0,%%r19),%%r14\n"
                      "\tldw 48(0,%%r19),%%r15\n"
                      "\tldw 52(0,%%r19),%%r16\n"
                      "\tldw 56(0,%%r19),%%r17\n"
                      "\tldw 60(0,%%r19),%%r18\n"
		      "\tldo 80(%%r19),%%r19\n"
		      "\tfldds -16(0,%%r19),%%fr12\n"
		      "\tfldds  -8(0,%%r19),%%fr13\n"
		      "\tfldds   0(0,%%r19),%%fr14\n"
		      "\tfldds   8(0,%%r19),%%fr15\n"
		      "\tldo 32(%%r19),%%r19\n"
		      "\tfldds -16(0,%%r19),%%fr16\n"
		      "\tfldds  -8(0,%%r19),%%fr17\n"
		      "\tfldds   0(0,%%r19),%%fr18\n"
		      "\tfldds   8(0,%%r19),%%fr19\n"
		      "\tldo 32(%%r19),%%r19\n"
		      "\tfldds -16(0,%%r19),%%fr20\n"
ken's avatar
ken committed
442
		      "\tfldds  -8(0,%%r19),%%fr21\n"
443
444
445
		         : "=r" (ret)
		         : "n" (-(116 * sizeof(long) + 10 * sizeof(double)))
		         : "%r19"
446
447
		      );

448
    return ret;
449
450
451
452
}

#endif /* hppa1_1_TARGET_ARCH */

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
/* -----------------------------------------------------------------------------
   PowerPC architecture

   We can use a simple function call as a tail call (the bl instruction places
   the return address in the Link Register, and we ignore it).
   We make GCC do the register saving. GCC does a good job
   and saves all general purpose registers with a single stmw
   (store multiple words) instruction.
   
   -------------------------------------------------------------------------- */

#ifdef powerpc_TARGET_ARCH

StgThreadReturnCode
StgRun(StgFunPtr f, StgRegTable *basereg) {

    unsigned char space[RESERVED_C_STACK_BYTES];

    f();
    __asm__ volatile (
	    ".align 4\n"
            ".globl " STG_RETURN "\n"
       	    STG_RETURN ":"
	    : : : 
			"r14","r15","r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","r26",
			"r27","r28","r29","r30","r31",
			"fr14","fr15","fr16","fr17","fr18","fr19","fr20",
			"fr21","fr22","fr23","fr24","fr25","fr26","fr27","fr28","fr29","fr30","fr31");
	   
    return (StgThreadReturnCode)R1.i;
}

#endif

487
#endif /* !USE_MINIINTERPRETER */
488