--FILE: RandomCodeRandomProceduresImpl.mesa
--Last Edited by: Sturgis, October 10, 1984 3:34:28 pm PDT
DIRECTORY
IO USING[STREAM],
RandomCodeRandom USING[Random, RandomState],
RandomCodeTypes USING[CreateSeqType, FillSeqType, GetLocalOffset, GetRemoteOffset, GetSeqTypeOfPointerType, GetSizeOfTypeSet, GetWordTypeFromIndex, SeqType, TypeSet, WordType],
RandomCodeTypedProgramGraphs USING[AssignRelativeGraphNodeAddresses, BeginTypeCheck, CreateProcedureGraph, DummyNodesTable, GenGraphBytes, GetDummyTableSize, GetRandomDummyTableEntry, InsertSFCallInDummyArc, InsertSourceReduction, InsertTargetReduction, InsertTestA, GetDummyNodeOpShape, OpDescriptor, OpTypeClass, PGNode, PrintGraph, PrintSortGraph, ProcedureInfo, RemoveNullDummy, SplitADummyArc, TearDownGraph, TopResultOfDummyOp, TopTwoArgsOfDummyOp],
RandomCodeDragonOps USING[GetEPOpForEntry, GetDragonOp, GetJBOpForJump, GetJDBOpForJump, GetRetOpForReturn, GetSFCOpForSFCall],
RandomCodeRandomProcedures USING[],
Rope USING[ROPE];
RandomCodeRandomProceduresImpl: CEDAR MONITOR IMPORTS RandomCodeRandom, RandomCodeTypes, RandomCodeTypedProgramGraphs, RandomCodeDragonOps EXPORTS RandomCodeRandomProcedures =
BEGIN
OPEN RandomCodeRandom, RandomCodeTypes, RandomCodeTypedProgramGraphs, RandomCodeDragonOps;
ProcedureBody: TYPE = REF ProcedureBodyData;
ProcedureBodyData: PUBLIC TYPE = RECORD[
procedureInfo: ProcedureInfo];
ProcTypeTable: TYPE = RECORD[SEQUENCE nProcTypes: CARDINAL OF WordType];
GenerateRandomProcedure: PUBLIC PROCEDURE[allowedArgs, possibleResults: SeqType, typeSet: TypeSet, randomState: RandomState] RETURNS[ProcedureBody, INT] =
BEGIN
procedure: ProcedureBody;
byteSize: INT;
table: DummyNodesTable;
tableSize: CARDINAL;
frameExtension: SeqType ← MakeRandomSeqType[typeSet, randomState];
procTypes: REF ProcTypeTable;
nProcTypes: CARDINAL;
RandomForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[Random[randomState]]};
LocalSelectSourceReductionOp: PROCEDURE[dummyOp: OpDescriptor, locals: SeqType, ordinaryWordType: WordType] RETURNS[OpDescriptor, --nPop-- CARDINAL] =
BEGIN
op: OpDescriptor; nPop: CARDINAL;
[op, nPop] ← GeneralSelectSourceReductionOp[dummyOp, locals, ordinaryWordType, randomState];
RETURN[op, nPop];
END;
LocalSelectTargetReductionOp: PROCEDURE[dummyOp: OpDescriptor, locals: SeqType, ordinaryWordType: WordType] RETURNS[OpDescriptor, --nPush-- CARDINAL] =
BEGIN
op: OpDescriptor; nPop: CARDINAL;
[op, nPop] ← GeneralSelectTargetReductionOp[dummyOp, locals, ordinaryWordType, randomState];
IF op = NIL THEN ERROR;
RETURN[op, nPop];
END;
SelectRandomProcType: PROCEDURE RETURNS[WordType] =
{RETURN[procTypes[Random[randomState] MOD procTypes.nProcTypes]]};
nProcTypes ← 0;
FOR I: CARDINAL IN [0..GetSizeOfTypeSet[typeSet]) DO
t: WordType ← GetWordTypeFromIndex[typeSet, I];
IF t.type = procedure THEN nProcTypes ← nProcTypes + 1;
ENDLOOP;
procTypes ← NEW[ProcTypeTable[nProcTypes]];
nProcTypes ← 0;
FOR I: CARDINAL IN [0..GetSizeOfTypeSet[typeSet]) DO
t: WordType ← GetWordTypeFromIndex[typeSet, I];
IF t.type = procedure THEN
BEGIN
procTypes[nProcTypes] ← t;
nProcTypes ← nProcTypes + 1;
END;
ENDLOOP;
[procedure, table] ← CreateNewProcedureBody[allowedArgs, frameExtension, possibleResults, typeSet, RandomForDragon];
TypeCheckProcedure[procedure];
WHILE (tableSize ← GetDummyTableSize[table]) < 50 DO -- this depends on initialized size of table
dummyNode: PGNode;
r: CARDINAL ← Random[randomState] MOD 1000;
IF tableSize = 0 THEN ERROR;
dummyNode ← GetRandomDummyTableEntry[table, Random[randomState]];
SELECT TRUE FROM
r < 100 =>
InsertSFCallInDummyArc[dummyNode, GetSFCOpForSFCall[], SelectRandomProcType[]];
r < 383 => InsertTestA[dummyNode, GetDragonOp[TestX, RandomForDragon, NIL, NIL, NIL], TRUE];
r < 716 => InsertTestA[dummyNode, GetDragonOp[TestX, RandomForDragon, NIL, NIL, NIL], FALSE];
ENDCASE =>
BEGIN
new: SeqType ← MakeRandomSeqType[typeSet, randomState];
SplitADummyArc[dummyNode, TRUE, 1, new];
END;
ENDLOOP;
WHILE GetDummyTableSize[table] # 0 DO
dummyNode: PGNode ← GetRandomDummyTableEntry[table, Random[randomState]];
nArgs, nResults: CARDINAL;
[nArgs, nResults] ← GetDummyNodeOpShape[dummyNode];
IF nArgs > 0 AND nResults > 0 THEN
BEGIN
IF Random[randomState] MOD 1000 > 499 THEN
InsertSourceReduction[dummyNode, LocalSelectSourceReductionOp]
ELSE InsertTargetReduction[dummyNode, LocalSelectTargetReductionOp]
END
ELSE IF nArgs > 0 THEN
InsertSourceReduction[dummyNode, LocalSelectSourceReductionOp]
ELSE IF nResults > 0 THEN
InsertTargetReduction[dummyNode, LocalSelectTargetReductionOp]
ELSE
RemoveNullDummy[dummyNode];
ENDLOOP;
byteSize ← AssignRelativeProcedureNodeAddresses[procedure];
RETURN[procedure, byteSize]
END;
CreateNewProcedureBody: PUBLIC PROCEDURE[allowedArgs, frameExtension, possibleResults: SeqType, typeSet: TypeSet, random: PROCEDURE RETURNS[CARDINAL]] RETURNS[ProcedureBody, DummyNodesTable] =
BEGIN
-- following procedures are to support the subsequent call to CreateProcedureGraph
getEPOpForEntry: PROCEDURE[nArgs: CARDINAL] RETURNS[OpDescriptor] =
{RETURN[GetEPOpForEntry[nArgs]]};
getDragonOp: PROCEDURE[
class: OpTypeClass,
random: PROCEDURE RETURNS[CARDINAL],
selectLocalIndex: PROCEDURE RETURNS[CARDINAL],
selectRemoteIndex: PROCEDURE RETURNS[CARDINAL],
selectLocalRemoteIndices: PROCEDURE RETURNS[l,r: CARDINAL]]
RETURNS[OpDescriptor] =
{RETURN[GetDragonOp[class, random, selectLocalIndex, selectRemoteIndex, selectLocalRemoteIndices]]};
getRetOpForReturn: PROCEDURE[nRetWords: CARDINAL] RETURNS[OpDescriptor] =
{RETURN[GetRetOpForReturn[nRetWords]]};
procedureInfo: ProcedureInfo ← CreateProcedureGraph[allowedArgs, frameExtension, possibleResults, typeSet, random, getEPOpForEntry, getDragonOp, getRetOpForReturn];
procedure: ProcedureBody ← NEW[ProcedureBodyData ← [procedureInfo]];
RETURN[procedure, procedureInfo.dummyNodesTable];
END;
PrintProcedureGraph: PUBLIC PROCEDURE[title: Rope.ROPE, procedure: ProcedureBody, on: IO.STREAM] =
BEGIN
IF NOT procedure.sorted THEN PrintSortGraph[procedure.entryNode];
PrintGraph[title, procedure.entryNode, on]
END;
GenProcedureBytes: PUBLIC PROCEDURE[procedure: ProcedureBody, oneByte: PROCEDURE[[0..255]]] =
BEGIN
IF NOT procedure.sorted THEN PrintSortGraph[procedure.entryNode];
GenGraphBytes[procedure.entryNode, oneByte]
END;
TypeCheckProcedure: PUBLIC PROCEDURE[procedure: ProcedureBody] =
{BeginTypeCheck[procedure.entryNode]};
AssignRelativeProcedureNodeAddresses: PUBLIC PROCEDURE[procedure: ProcedureBody] RETURNS[size: INT] =
-- may have to install some extra jumps, or modify some conditional jumps
BEGIN
IF NOT procedure.sorted THEN PrintSortGraph[procedure.entryNode];
RETURN[AssignRelativeGraphNodeAddresses[procedure.entryNode, GetJBOpForJump, GetJDBOpForJump]];
END;
TearDownProcedure: PUBLIC PROCEDURE[procedure: ProcedureBody] =
BEGIN
IF NOT procedure.sorted THEN PrintSortGraph[procedure.entryNode];
TearDownGraph[procedure.entryNode];
END;
MakeRandomSeqType: PROCEDURE[typeSet: TypeSet, randomState: RandomState] RETURNS[SeqType] =
BEGIN
seqSize: CARDINAL ← Random[randomState] MOD 5;
seq: SeqType ← CreateSeqType[typeSet, NIL, seqSize];
typeSetSize: CARDINAL ← GetSizeOfTypeSet[typeSet];
genWType: PROCEDURE[i: CARDINAL] RETURNS[WordType] =
BEGIN
x: CARDINAL ← Random[randomState] MOD typeSetSize;
t: WordType ← GetWordTypeFromIndex[typeSet, x];
WHILE t.type = uninitialized DO
x ← Random[randomState] MOD typeSetSize;
t ← GetWordTypeFromIndex[typeSet, x];
ENDLOOP;
RETURN[t];
END;
FillSeqType[seq, genWType];
RETURN[seq];
END;
GeneralSelectSourceReductionOp: PROCEDURE[dummyOp: OpDescriptor, locals: SeqType, ordinaryWordType: WordType, randomState: RandomState] RETURNS[OpDescriptor, --nPop-- CARDINAL] =
BEGIN
RandomForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[Random[randomState]]};
SelectLocalWIndexForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[GetLocalOffset[locals, ordinaryWordType, Random[randomState]]]};
SelectNilLocalIndexForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[LAST[CARDINAL]]};
SelectLocalS0IndexForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[GetLocalOffset[locals, s0, Random[randomState]]]};
s0, s1: WordType;
[s0, s1] ← TopTwoArgsOfDummyOp[dummyOp];
IF s0 = NIL THEN RETURN[NIL, 0];
-- possible allowed ops affect the stack by popping off the s0, or by replacing <s0,s1> by <s1> or nothing. s0 is never NIL, but s1 may be NIL.
IF s1 # NIL THEN -- see if we can insert an op which replaces top two of stack by one or zero. We treat exactly two cases: arithmetic operations on ordinary words, or storing through a pointer.
BEGIN
SELECT s1.type FROM
ordinary =>
BEGIN
SELECT s0.type FROM
ordinary =>
BEGIN -- we do some arithmetic
op: OpDescriptor ← GetDragonOp[PopWW, RandomForDragon, SelectLocalWIndexForDragon, NIL, NIL];
IF op # NIL THEN RETURN[op, 2];
END;
ENDCASE => NULL;
END;
pointer =>
BEGIN -- find a suitable field within s1 at which to store s0
remoteSeq: SeqType ← GetSeqTypeOfPointerType[s1];
offset: CARDINAL ← GetLocalOffset[remoteSeq, s0, Random[randomState]];
op: OpDescriptor ← NIL;
SelectRemoteTIndexForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[offset]};
IF offset # LAST[CARDINAL] THEN
op ← GetDragonOp[PopSIT, RandomForDragon, NIL, SelectRemoteTIndexForDragon, NIL];
IF op # NIL THEN RETURN[op, 2];
END;
ENDCASE => NULL;
END;
-- at this point we know that there is at least one item on top of stack
SELECT s0.type FROM
ordinary =>
BEGIN -- we do some arithmetic
op: OpDescriptor ← GetDragonOp[PopW, RandomForDragon, SelectLocalWIndexForDragon, NIL, NIL];
IF op # NIL THEN RETURN[op, 1];
END;
ENDCASE => NULL;
-- finally, we try removing the top of stack by storing it locally
BEGIN
op: OpDescriptor ← GetDragonOp[PopT, RandomForDragon, SelectLocalS0IndexForDragon, NIL, NIL];
IF op # NIL THEN RETURN[op, 1];
END;
-- if all else fails, we just remove the top of stack by popping it.
BEGIN
op: OpDescriptor ← GetDragonOp[PopW, RandomForDragon, SelectNilLocalIndexForDragon, NIL, NIL];
IF op # NIL THEN RETURN[op, 1];
END;
ERROR;
END;
GeneralSelectTargetReductionOp: PROCEDURE[dummyOp: OpDescriptor, locals: SeqType, ordinaryWordType: WordType, randomState: RandomState] RETURNS[OpDescriptor, --nPush-- CARDINAL] =
BEGIN
RandomForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[Random[randomState]]};
SelectLocalWIndexForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[GetLocalOffset[locals, ordinaryWordType, Random[randomState]]]};
SelectLocalTIndexForDragon: PROCEDURE RETURNS[CARDINAL] =
{RETURN[GetLocalOffset[locals, t0, Random[randomState]]]};
t0: WordType;
t0 ← TopResultOfDummyOp[dummyOp];
IF t0 = NIL THEN RETURN[NIL, 0];
-- all allowed ops load <t0> onto the stack.
-- first see if t0 is ordinary
IF t0.type = ordinary THEN
BEGIN
op: OpDescriptor ← GetDragonOp[PushW, RandomForDragon, SelectLocalWIndexForDragon, NIL, NIL];
IF op # NIL THEN RETURN[op, 1];
END;
-- next see if we can find a local t0
BEGIN
op: OpDescriptor ← GetDragonOp[PushT, RandomForDragon, SelectLocalTIndexForDragon, NIL, NIL];
IF op # NIL THEN RETURN[op, 1];
END;
-- now see if we can find a remote t0, one indirection remote
BEGIN
localOffset: CARDINAL;
remoteOffset: CARDINAL;
SelectLocalRemoteIndexForDragon: PROCEDURE RETURNS[l,r: CARDINAL] =
{RETURN[localOffset, remoteOffset]};
[localOffset, remoteOffset] ← GetRemoteOffset[locals, t0, Random[randomState]];
IF localOffset # LAST[CARDINAL] THEN
BEGIN
op: OpDescriptor ← GetDragonOp[PushFIT, RandomForDragon, NIL, NIL, SelectLocalRemoteIndexForDragon];
IF op # NIL THEN RETURN[op, 1];
END;
END;
-- can't see how to do it for now
ERROR;
END;
END.
MODULE HISTORY
Initial by: Sturgis, October 8, 1984 11:41:09 am PDT, from RandomGraphs?