Add tests for C <setjmp.h> and Modula-2 Semaphores.
Fix PowerPC ncg so setjmp() returns the correct value. I got unlucky when ncg picked r3 for "uses REG"; this destroyed the return value in r3 and caused the new test to fail.
This commit is contained in:
parent
26de4c1ab1
commit
d6938108a6
|
@ -85,9 +85,8 @@ REGISTERS
|
||||||
lr, ctr : SPR.
|
lr, ctr : SPR.
|
||||||
cr0 : CR.
|
cr0 : CR.
|
||||||
|
|
||||||
/* The stacking rules and the splitting coercions can't
|
/* The stacking rules can't allocate registers. We use these
|
||||||
* allocate registers. We use r12 in the splitting coercions,
|
* scratch registers to stack tokens.
|
||||||
* and these scratch registers in the stacking rules.
|
|
||||||
*/
|
*/
|
||||||
#define RSCRATCH r0
|
#define RSCRATCH r0
|
||||||
#define FSCRATCH f0
|
#define FSCRATCH f0
|
||||||
|
@ -2192,15 +2191,21 @@ PATTERNS
|
||||||
pat lpb /* LB -> argument base */
|
pat lpb /* LB -> argument base */
|
||||||
leaving adp EM_BSIZE
|
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 */
|
pat gto /* longjmp */
|
||||||
with STACK
|
with STACK
|
||||||
uses REG
|
|
||||||
gen
|
gen
|
||||||
move {LABEL, $1}, %a
|
move {LABEL, $1}, r12
|
||||||
move {IND_RC_W, %a, 8}, fp
|
move {IND_RC_W, r12, 8}, fp
|
||||||
move {IND_RC_W, %a, 4}, sp
|
move {IND_RC_W, r12, 4}, sp
|
||||||
move {IND_RC_W, %a, 0}, %a
|
move {IND_RC_W, r12, 0}, r12
|
||||||
mtspr ctr, %a
|
mtspr ctr, r12
|
||||||
bctr.
|
bctr.
|
||||||
|
|
||||||
pat lor $1==0 /* Load local base */
|
pat lor $1==0 /* Load local base */
|
||||||
|
|
|
@ -22,6 +22,7 @@ definerule("plat_testsuite",
|
||||||
"tests/plat/m2/ConvTest_mod.mod",
|
"tests/plat/m2/ConvTest_mod.mod",
|
||||||
"tests/plat/m2/NestProc_mod.mod",
|
"tests/plat/m2/NestProc_mod.mod",
|
||||||
"tests/plat/m2/OpenArray_mod.mod",
|
"tests/plat/m2/OpenArray_mod.mod",
|
||||||
|
"tests/plat/m2/SemaTest_mod.mod",
|
||||||
"tests/plat/m2/Set100_mod.mod",
|
"tests/plat/m2/Set100_mod.mod",
|
||||||
"tests/plat/m2/StringTest_mod.mod"
|
"tests/plat/m2/StringTest_mod.mod"
|
||||||
)
|
)
|
||||||
|
|
157
tests/plat/m2/SemaTest_mod.mod
Normal file
157
tests/plat/m2/SemaTest_mod.mod
Normal file
|
@ -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.
|
58
tests/plat/setjmp_c.c
Normal file
58
tests/plat/setjmp_c.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include <setjmp.h>
|
||||||
|
#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();
|
||||||
|
}
|
Loading…
Reference in a new issue