diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 10ffadb16..a35ace230 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -85,9 +85,8 @@ REGISTERS lr, ctr : SPR. cr0 : CR. - /* The stacking rules and the splitting coercions can't - * allocate registers. We use r12 in the splitting coercions, - * and these scratch registers in the stacking rules. + /* The stacking rules can't allocate registers. We use these + * scratch registers to stack tokens. */ #define RSCRATCH r0 #define FSCRATCH f0 @@ -2192,15 +2191,21 @@ PATTERNS pat lpb /* LB -> argument base */ leaving adp EM_BSIZE + /* "gto" must preserve the function result for "lfr", so + * longjmp() can pass the return value to setjmp(). + * - See lang/cem/libcc.ansi/setjmp/setjmp.e + * + * Must preserve r3 and r4, so no "uses REG". + * PowerPC can't add r0 + constant. Use r12. + */ pat gto /* longjmp */ with STACK - uses REG gen - move {LABEL, $1}, %a - move {IND_RC_W, %a, 8}, fp - move {IND_RC_W, %a, 4}, sp - move {IND_RC_W, %a, 0}, %a - mtspr ctr, %a + move {LABEL, $1}, r12 + move {IND_RC_W, r12, 8}, fp + move {IND_RC_W, r12, 4}, sp + move {IND_RC_W, r12, 0}, r12 + mtspr ctr, r12 bctr. pat lor $1==0 /* Load local base */ diff --git a/tests/plat/build.lua b/tests/plat/build.lua index fdac9bae3..42ca441d0 100644 --- a/tests/plat/build.lua +++ b/tests/plat/build.lua @@ -22,6 +22,7 @@ definerule("plat_testsuite", "tests/plat/m2/ConvTest_mod.mod", "tests/plat/m2/NestProc_mod.mod", "tests/plat/m2/OpenArray_mod.mod", + "tests/plat/m2/SemaTest_mod.mod", "tests/plat/m2/Set100_mod.mod", "tests/plat/m2/StringTest_mod.mod" ) diff --git a/tests/plat/m2/SemaTest_mod.mod b/tests/plat/m2/SemaTest_mod.mod new file mode 100644 index 000000000..9ae395662 --- /dev/null +++ b/tests/plat/m2/SemaTest_mod.mod @@ -0,0 +1,157 @@ +(* + * Generates some integer sequences. Each generator is a process that + * yields integers to the main process. ACK switches processes by + * saving and restoring the stack. It uses _lor_ and _str_ to save + * and restore the local base and frame pointer. + *) +MODULE SemaTest; +FROM Semaphores IMPORT Sema, NewSema, Down, Up, StartProcess; +FROM Storage IMPORT ALLOCATE; +FROM Test IMPORT fail, finished; + +TYPE + Generator = POINTER TO GeneratorRecord; + GeneratorRecord = RECORD + resume: Sema; (* up when resuming generator *) + yield: Sema; (* up when yielding value *) + value: INTEGER; + END; +VAR + curgen: Generator; (* current generator *) + startLock: Sema; (* down when booting generator *) + startProc: PROC; + startSelf: Generator; + +PROCEDURE BootGenerator; + VAR pr: PROC; self: Generator; +BEGIN + pr := startProc; + self := startSelf; + Up(startLock); + Down(self^.resume); (* wait for first Resume *) + pr(); +END BootGenerator; + +PROCEDURE StartGenerator(gen: Generator; pr: PROC); +BEGIN + gen^.resume := NewSema(0); + gen^.yield := NewSema(0); + Down(startLock); + startProc := pr; + startSelf := gen; + StartProcess(BootGenerator, 8192); +END StartGenerator; + +PROCEDURE Resume(gen: Generator): INTEGER; + VAR self: Generator; +BEGIN + self := curgen; + curgen := gen; + Up(gen^.resume); + Down(gen^.yield); (* wait for Yield *) + curgen := self; + RETURN gen^.value +END Resume; + +PROCEDURE Yield(i: INTEGER); + VAR self: Generator; +BEGIN + self := curgen; + self^.value := i; + Up(self^.yield); (* curgen becomes invalid *) + Down(self^.resume); (* wait for Resume *) +END Yield; + +PROCEDURE YieldHalfOf(i: INTEGER); +BEGIN + Yield(i DIV 2); +END YieldHalfOf; + +PROCEDURE Triangular; + (* Yields the triangular numbers, http://oeis.org/A000217 *) + VAR n: INTEGER; +BEGIN + n := 0; + LOOP + YieldHalfOf(n * (n + 1)); + INC(n); + END; +END Triangular; + +PROCEDURE Pentagonal; + (* Yields the pentagonal numbers, http://oeis.org/A000326 *) + VAR n: INTEGER; +BEGIN + n := 0; + LOOP + YieldHalfOf(n * (3 * n - 1)); + INC(n); + END; +END Pentagonal; + +PROCEDURE Odious; + (* Yields the odius numbers, http://oeis.org/A000069 *) + VAR b, i, n: INTEGER; +BEGIN + n := 1; + LOOP + (* b := count bits in n *) + b := 0; + i := n; + WHILE i # 0 DO + INC(b, i MOD 2); + i := i DIV 2; + END; + + IF (b MOD 2) = 1 THEN + Yield(n); + END; + INC(n); + END; +END Odious; + +TYPE + Triple = ARRAY[1..3] OF INTEGER; +PROCEDURE T(i1, i2, i3: INTEGER): Triple; + VAR t: Triple; +BEGIN + t[1] := i1; t[2] := i2; t[3] := i3; RETURN t +END T; + +CONST + two28 = 268435456D; (* 0x1000_0000 *) +VAR + a: ARRAY [0..9] OF Triple; + tri, pen, odi: Generator; + i, g1, g2, g3: INTEGER; +BEGIN + startLock := NewSema(1); + + ALLOCATE(tri, SIZE(GeneratorRecord)); + ALLOCATE(pen, SIZE(GeneratorRecord)); + ALLOCATE(odi, SIZE(GeneratorRecord)); + StartGenerator(tri, Triangular); + StartGenerator(pen, Pentagonal); + StartGenerator(odi, Odious); + + a[0] := T( 0, 0, 1); + a[1] := T( 1, 1, 2); + a[2] := T( 3, 5, 4); + a[3] := T( 6, 12, 7); + a[4] := T(10, 22, 8); + a[5] := T(15, 35, 11); + a[6] := T(21, 51, 13); + a[7] := T(28, 70, 14); + a[8] := T(36, 92, 16); + a[9] := T(45, 117, 19); + + FOR i := 0 TO INTEGER(9) DO + g1 := Resume(tri); + g2 := Resume(pen); + g3 := Resume(odi); + IF g1 # a[i][1] THEN fail(1D * two28 + LONG(a[i][1])) END; + IF g2 # a[i][2] THEN fail(2D * two28 + LONG(a[i][2])) END; + IF g3 # a[i][3] THEN fail(3D * two28 + LONG(a[i][3])) END; + END; + finished; +END SemaTest. diff --git a/tests/plat/setjmp_c.c b/tests/plat/setjmp_c.c new file mode 100644 index 000000000..2a514a03f --- /dev/null +++ b/tests/plat/setjmp_c.c @@ -0,0 +1,58 @@ +#include +#include "test.h" + +/* + * Sets i = 2 * i for each i in nums, until i == 0, but stops if + * 2 * i >= 1000. + * + * Uses setjmp() and longjmp() in libc. For ACK's libc, the back end + * must provides EM's _gto_, and _gto_ must preserve the function + * return area. + */ +int nums1[] = { 79, 245, 164, 403, 0}; +const int expect1[] = {158, 490, 328, 806, 0}; +int nums2[] = {20, 221, 411, 643, 48, 272, 448, 0}; +const int expect2[] = {40, 442, 822, 643, 48, 272, 448, 0}; +int nums3[] = {371, 265, 500, 124, 117, 0}; +const int expect3[] = {742, 530, 500, 124, 117, 0}; +int docount = 0; + +int twice(int i, jmp_buf esc) { + if (i >= 500) + longjmp(esc, i); + return 2 * i; +} + +void donums(int *nums, jmp_buf esc) { + int *p; + + docount++; + for (p = nums; *p != 0; p++) { + *p = twice(*p, esc); + } +} + +int cknums(int *nums, const int *expect) { + jmp_buf env; + int ret; + + ret = setjmp(env); + if (ret == 0) + donums(nums, env); + for (;;) { + ASSERT(*nums == *expect); + if (*expect == 0) + break; + nums++; + expect++; + } + return ret; +} + +int main(void) { + ASSERT(cknums(nums1, expect1) == 0); + ASSERT(cknums(nums2, expect2) == 643); + ASSERT(cknums(nums3, expect3) == 500); + ASSERT(docount == 3); + finished(); +}