StgCRun.c 15.8 KB
 simonm committed Dec 02, 1998 1 /* -----------------------------------------------------------------------------  simonmar committed Mar 26, 2002 2  * $Id: StgCRun.c,v 1.31 2002/03/26 10:35:20 simonmar Exp$  simonm committed Feb 05, 1999 3  *  simonmar committed Mar 07, 2000 4  * (c) The GHC Team, 1998-2000  simonm committed Dec 02, 1998 5  *  simonmar committed Mar 07, 2000 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 committed Jan 07, 2002 22  * other registers (other than saving the C callee-saves  simonmar committed Mar 07, 2000 23 24  * registers). Instead, the called function "f" must do that * in STG land.  ken committed Jan 07, 2002 25  *  simonmar committed Mar 07, 2000 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 committed Jan 07, 2002 32  * variables.  simonm committed Dec 02, 1998 33 34 35  * * -------------------------------------------------------------------------- */  sewardj committed Aug 14, 2001 36 37 #include "PosixSource.h"  ken committed Aug 07, 2001 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 committed Jan 07, 2002 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 committed Aug 07, 2001 52 53 54  */ #include "config.h" #ifdef alpha_TARGET_ARCH  ken committed Jan 07, 2002 55 #define alpha_EXTRA_CAREFUL  ken committed Aug 07, 2001 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  simonm committed Dec 02, 1998 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 committed Jan 07, 2002 82   sof committed Feb 28, 2002 83 extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg STG_UNUSED)  simonm committed Dec 02, 1998 84 {  sewardj committed Apr 17, 2000 85 86 87  while (f) { IF_DEBUG(evaluator, fprintf(stderr,"Jumping to ");  sof committed Feb 28, 2002 88  printPtr((P_)f); fflush(stdout);  sewardj committed Apr 17, 2000 89  fprintf(stderr,"\n");  sewardj committed Apr 17, 2000 90 91 92 93  ); f = (StgFunPtr) (f)(); } return (StgThreadReturnCode)R1.i;  simonm committed Dec 02, 1998 94 95 96 97 } EXTFUN(StgReturn) {  sewardj committed Apr 17, 2000 98  return 0;  simonm committed Dec 02, 1998 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  simonmar committed Mar 07, 2000 109 110 111 /* ----------------------------------------------------------------------------- x86 architecture -------------------------------------------------------------------------- */  ken committed Jan 07, 2002 112   simonmar committed Mar 07, 2000 113 114 115 116 117 #ifdef i386_TARGET_ARCH StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg) {  qrczak committed Aug 07, 2000 118  unsigned char space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ];  simonmar committed Mar 07, 2000 119 120 121  StgThreadReturnCode r; __asm__ volatile (  ken committed Jan 07, 2002 122  /*  simonmar committed Mar 07, 2000 123 124 125  * save callee-saves registers on behalf of the STG code. */ "movl %%esp, %%eax\n\t"  sewardj committed Feb 08, 2002 126  "addl %4, %%eax\n\t"  simonmar committed Mar 07, 2000 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 */  sewardj committed Feb 08, 2002 134  "movl %3,%%ebx\n\t"  simonmar committed Mar 07, 2000 135  /*  sewardj committed Feb 08, 2002 136  * grab the function argument from the stack, and jump to it.  simonmar committed Mar 07, 2000 137  */  sewardj committed Feb 08, 2002 138  "movl %2,%%eax\n\t"  simonmar committed Mar 07, 2000 139 140 141 142  "jmp *%%eax\n\t" ".global " STG_RETURN "\n" STG_RETURN ":\n\t"  sewardj committed Feb 08, 2002 143 144 145  "movl %%esi, %%eax\n\t" /* Return value in R1 */  simonmar committed Mar 07, 2000 146 147 148 149  /* * restore callee-saves registers. (Don't stomp on %%eax!) */ "movl %%esp, %%edx\n\t"  sewardj committed Feb 08, 2002 150  "addl %4, %%edx\n\t"  simonmar committed Mar 07, 2000 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"  sewardj committed Feb 08, 2002 156 157  : "=&a" (r), "=m" (space) : "m" (f), "m" (basereg), "i" (RESERVED_C_STACK_BYTES)  simonmar committed Mar 07, 2000 158 159 160 161 162 163 164 165  : "edx" /* stomps on %edx */ ); return r; } #endif  simonm committed Dec 02, 1998 166 /* -----------------------------------------------------------------------------  simonmar committed Mar 08, 2000 167 168  Sparc architecture  ken committed Jan 07, 2002 169  --  simonmar committed Mar 08, 2000 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  simonmar committed Nov 13, 2000 194  Updated info (GHC 4.08.2): not saving %i7 any more (see below).  simonm committed Dec 02, 1998 195  -------------------------------------------------------------------------- */  ken committed Jan 07, 2002 196   simonm committed Dec 02, 1998 197 198 199 #ifdef sparc_TARGET_ARCH StgThreadReturnCode  simonmar committed Nov 03, 1999 200 StgRun(StgFunPtr f, StgRegTable *basereg) {  simonm committed Dec 02, 1998 201   simonmar committed Dec 04, 2000 202 203 204 205 206  unsigned char space[RESERVED_C_STACK_BYTES]; #if 0 register void *i7 __asm__("%i7"); ((void **)(space))[100] = i7; #endif  simonm committed Dec 02, 1998 207  f();  simonmar committed Mar 08, 2000 208  __asm__ volatile (  ken committed Jan 07, 2002 209  ".align 4\n"  simonm committed Dec 02, 1998 210  ".global " STG_RETURN "\n"  ken committed Jan 07, 2002 211  STG_RETURN ":"  simonmar committed Mar 08, 2000 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. */  simonmar committed Nov 13, 2000 223 #if 0  simonmar committed Nov 13, 2000 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 committed Jan 07, 2002 229  __asm__ volatile ("ld %1,%0"  simonmar committed Mar 08, 2000 230  : "=r" (i7) : "m" (((void **)(space))[100]));  simonmar committed Nov 13, 2000 231 #endif  simonm committed Dec 02, 1998 232 233 234 235 236 237 238  return (StgThreadReturnCode)R1.i; } #endif /* ----------------------------------------------------------------------------- alpha architecture  ken committed Aug 07, 2001 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 committed Jan 07, 2002 260  -- Compaq Computer Corporation, Houston. Tru64 UNIX Calling Standard for  ken committed Aug 07, 2001 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  simonm committed Dec 02, 1998 263 264 265 266 267  -------------------------------------------------------------------------- */ #ifdef alpha_TARGET_ARCH StgThreadReturnCode  ken committed Jan 07, 2002 268 StgRun(StgFunPtr f, StgRegTable *basereg)  simonm committed Dec 02, 1998 269 {  ken committed Aug 07, 2001 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 committed Jan 07, 2002 281   ken committed Aug 07, 2001 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");  simonmar committed Dec 01, 1999 295 296  StgThreadReturnCode ret;  ken committed Aug 07, 2001 297  save_ra = real_ra;  simonm committed Dec 02, 1998 298   ken committed Aug 07, 2001 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  simonm committed Dec 02, 1998 352   ken committed Aug 07, 2001 353  real_ra = save_ra;  simonm committed Dec 02, 1998 354   simonmar committed Dec 01, 1999 355  return ret;  simonm committed Dec 02, 1998 356 357 }  simonm committed Mar 11, 1999 358 #endif /* alpha_TARGET_ARCH */  simonm committed Dec 02, 1998 359   simonm committed Mar 01, 1999 360 361 362 363 364 365 366 /* ----------------------------------------------------------------------------- HP-PA architecture -------------------------------------------------------------------------- */ #ifdef hppa1_1_TARGET_ARCH StgThreadReturnCode  ken committed Jan 07, 2002 367 StgRun(StgFunPtr f, StgRegTable *basereg)  simonm committed Mar 01, 1999 368 369 { StgChar space[RESERVED_C_STACK_BYTES+16*sizeof(long)+10*sizeof(double)];  simonmar committed Jul 27, 1999 370  StgThreadReturnCode ret;  simonm committed Mar 11, 1999 371   simonm committed Mar 01, 1999 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" */  simonm committed Mar 11, 1999 412 413  "\tldo %1(%%r30),%%r19\n" "\tcopy %%r11, %0\n" /* save R1 */  simonm committed Mar 01, 1999 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 committed Jan 07, 2002 442  "\tfldds -8(0,%%r19),%%fr21\n"  simonmar committed Jul 27, 1999 443 444 445  : "=r" (ret) : "n" (-(116 * sizeof(long) + 10 * sizeof(double))) : "%r19"  simonm committed Mar 01, 1999 446 447  );  simonm committed Mar 11, 1999 448  return ret;  simonm committed Mar 01, 1999 449 450 451 452 } #endif /* hppa1_1_TARGET_ARCH */  simonmar committed Mar 26, 2002 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  simonm committed Dec 02, 1998 487 #endif /* !USE_MINIINTERPRETER */ ` simonmar committed Mar 26, 2002 488