
Thiemo Seufer wrote:
Hello All,
I currently try to get a ghc port on mips-linux going. I understand Igloo does the same ATM, and things look promising so far.
However, the port is currently unregisterised, and I would like to improve it a bit. A registerised port seems to be achievable with a moderate amount of work. I looked a bit around in the code, and have now a few questions:
- The example of other ports suggests the useful maximum of general purpose registers for GHC is 8. I also presume that unmentioned registers aren't touched by haskell code. Is this correct?
- The comments in the source suggest that callee-saved registers are preferable, without further explanation. I would expect a mix of caller- and callee-saved registers to be potentially better. Any advice on this?
- The mips ABI defines 8 (or 9 when including the frame pointer) registers as callee-saved, and more than 9 caller-saved temporaries. With four registers taken for stack/heap pointers this leaves a 5/3 split of callee-saved/caller-saved registers, if all my assumptions above are ok. Are there other considerations to take into account for the register layout?
I decided to ignore the performance tuning for now and used a register mapping which is compatible to all three relevant MIPS ABIs. It uses 4 callee-saved registers as R1-R4, plus 4 temporaries (caller-saved) registers as R5-R8. With the appended patch to support a registerised build of GHC 6.4.2 on Debian mips-linux I got those testsuite results: OVERALL SUMMARY for test run started at Wed Aug 23 20:12:05 BST 2006 674 total tests, which gave rise to 1883 test cases, of which 21 caused framework failures 369 were skipped 1407 expected passes 22 expected failures 0 unexpected passes 41 unexpected failures Unexpected failures: barton-mangler-bug(normal,opt,prof,threaded) cabal01(normal) cg005(prof) char001(prof) directory001(prof) driver062.2(normal) drvrun006(normal) drvrun018(opt) enum02(threaded) exceptions001(normal) ext1(prof) fed001(normal,opt,prof,threaded) ffi006(normal,opt,prof,threaded) ffi007(normal,opt,prof,threaded) ffi008(normal) finalization001(threaded) freeNames(threaded) galois_raytrace(opt,prof) ioref001(normal,prof,threaded) joao-circular(normal,opt,prof,threaded) ratio001(prof) uri001(prof) xmlish(prof) Not all that bad for a first attempt. Some of the failures are probably due to the lack of MIPS support in ghc/rts/Adjustor.c, AFAIU this means C -> haskell calls don't work for now. I made ghc6 .deb packages from the unmodified Debian source, another set of packages built with the appended patch, plus a haddock package which is needed as a build-dependency. All are available from http://people.debian.org/~ths/ghc6/ and http://people.debian.org/~ths/haddock/ There are no little endian mipsel packages yet. So if you happen to have a Debian mips installation around and want to try ghc6, feel free. :-) Thiemo diff -urpN restrap2/ghc6-6.4.2/ghc/includes/MachRegs.h hackage/ghc6-6.4.2/ghc/includes/MachRegs.h --- restrap2/ghc6-6.4.2/ghc/includes/MachRegs.h 2005-07-13 09:47:05.000000000 +0100 +++ hackage/ghc6-6.4.2/ghc/includes/MachRegs.h 2006-08-22 21:42:31.000000000 +0100 @@ -399,10 +399,6 @@ #define REG(x) __asm__("$" #x) -#define CALLER_SAVES_R1 -#define CALLER_SAVES_R2 -#define CALLER_SAVES_R3 -#define CALLER_SAVES_R4 #define CALLER_SAVES_R5 #define CALLER_SAVES_R6 #define CALLER_SAVES_R7 @@ -410,14 +406,14 @@ #define CALLER_SAVES_USER -#define REG_R1 9 -#define REG_R2 10 -#define REG_R3 11 -#define REG_R4 12 -#define REG_R5 13 -#define REG_R6 14 -#define REG_R7 15 -#define REG_R8 24 +#define REG_R1 16 +#define REG_R2 17 +#define REG_R3 18 +#define REG_R4 19 +#define REG_R5 12 +#define REG_R6 13 +#define REG_R7 14 +#define REG_R8 15 #define REG_F1 f20 #define REG_F2 f22 @@ -427,11 +423,13 @@ #define REG_D1 f28 #define REG_D2 f30 -#define REG_Sp 16 -#define REG_SpLim 18 +#define REG_Sp 20 +#define REG_SpLim 21 -#define REG_Hp 19 -#define REG_HpLim 20 +#define REG_Hp 22 +#define REG_HpLim 23 + +#define REG_Base 30 #endif /* mipse[lb] */ diff -urpN restrap2/ghc6-6.4.2/ghc/includes/TailCalls.h hackage/ghc6-6.4.2/ghc/includes/TailCalls.h --- restrap2/ghc6-6.4.2/ghc/includes/TailCalls.h 2005-03-08 09:38:57.000000000 +0000 +++ hackage/ghc6-6.4.2/ghc/includes/TailCalls.h 2006-08-22 20:45:52.000000000 +0100 @@ -245,6 +245,29 @@ but uses $$dyncall if necessary to cope, #endif /* ----------------------------------------------------------------------------- + Tail calling on MIPS + -------------------------------------------------------------------------- */ + +#ifdef mips_HOST_ARCH + +#if IN_STG_CODE +register void *_procedure __asm__("$25"); +#endif + +#define JMP_(cont) \ + { \ + _procedure = (void *)(cont); \ + __DISCARD__(); \ + goto *_procedure; \ + } + +/* Don't need these for MIPS mangling */ +#define FB_ +#define FE_ + +#endif /* mips_HOST_ARCH */ + +/* ----------------------------------------------------------------------------- FUNBEGIN and FUNEND. These are markers indicating the start and end of Real Code in a diff -urpN restrap2/ghc6-6.4.2/ghc/rts/StgCRun.c hackage/ghc6-6.4.2/ghc/rts/StgCRun.c --- restrap2/ghc6-6.4.2/ghc/rts/StgCRun.c 2006-03-22 10:29:51.000000000 +0000 +++ hackage/ghc6-6.4.2/ghc/rts/StgCRun.c 2006-08-22 21:54:33.000000000 +0100 @@ -877,4 +877,37 @@ StgRunIsImplementedInAssembler(void) #endif +/* ----------------------------------------------------------------------------- + MIPS architecture + -------------------------------------------------------------------------- */ + +#ifdef mips_HOST_ARCH + +StgThreadReturnCode +StgRun(StgFunPtr f, StgRegTable *basereg) +{ + register StgThreadReturnCode __v0 __asm__("$2"); + + __asm__ __volatile__( + " la $25, %1 \n" + " move $30, %2 \n" + " jr %1 \n" + " .align 3 \n" + " .globl " STG_RETURN " \n" + " .aent " STG_RETURN " \n" + STG_RETURN ": \n" + " move %0, $16 \n" + " move $3, $17 \n" + : "=r" (__v0), + : "r" (f), "r" (basereg) + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$25", "$28", "$30", + "$f20", "$f22", "$f24", "$f26", "$f28", "$f30", + "memory"); + + return __v0; +} + +#endif /* mips_HOST_ARCH */ + #endif /* !USE_MINIINTERPRETER */