--FILE: RandomCodeTypedProgramGraphsImpl.mesa
--Last Edited by: Sturgis, April 26, 1984 9:24:24 am PST
-- comment: May 7, 1984 3:50:47 pm PDT: must change the frame model to combine local vars and expression stack? without losing the information tables?
-- currentActivity: April 25, 1984 2:29:18 pm PST: simplifying the graph modification procedures. Yet to do: move op creation code to the individual op sections
-- remark: April 18, 1984 4:39:03 pm PST: Have to worry about not having to re-sort each time I want to print etc to avoid high unneeded costs, but must re-sort at each graph change?.
DIRECTORY
IO USING[card, int, PutF, rope, STREAM],
RandomCodeTypes USING[ArgPairTypeCheck, ArgSeqTypeCheck, CopySeqType, CopyWithOneTypeChanged, CreateSeqType, CreateTypeExtendingPartOfType, FillSeqType, FindFirstDiff, FrameVarsCheck, GetArgsResultsOfProcedureType, GetLength, GetLocalOffset, GetRemoteOffset, GetOrdinaryWordType, GetTypeSetOfSeq, GetWordTypeFromOffset, LoadIndirectTypeCheck, MergeTypes, PopSomeTypes, PrintSeqType, PushOneType, ResultSeqTypeCheck, ResultWordTypeCheck, SeqType, StackBaseCheck, StoreIndirectTypeCheck, SubtractAddTypes, TopOfSeq, TopTwoOfSeq, TypeSet, WordStorableAs, WordType],
RandomCodeTypedProgramGraphs USING[ArcNumber, DummyNodesTable, DummyNodesTableBody, DummyNodesTableArray, LoadStore, OpDescriptor, OpDescriptorBody, OpKind, OpKindBody, OpTypeClass, ProcedureInfo, ProcedureInfoBody],
Rope USING[ROPE];
RandomCodeTypedProgramGraphsImpl: CEDAR MONITOR IMPORTS IO, RandomCodeTypes EXPORTS RandomCodeTypedProgramGraphs =
BEGIN
OPEN RandomCodeTypes, RandomCodeTypedProgramGraphs;
-- program graph nodes
PGNode: TYPE = REF PGNodeBody;
PGNodeBody: PUBLIC TYPE = RECORD[
frameVarsState: SeqType ← NIL,
stackState: SeqType ← NIL,
op: OpDescriptor ← NIL,
arcs: ARRAY ArcNumber OF PGNode ← [NIL, NIL],
typeCheckPass: LONG CARDINAL ← 0,
procedureInfo: ProcedureInfo ← NIL,
dummyTableIndex: CARDINAL ← 0,
relativeAddress: INT ← 0,
-- following is info used during print sorting
backArcs: ARRAY ArcNumber OF BOOLEAN ← [FALSE, FALSE],
scanNumb: CARDINAL ← 0,
nFwdArcs: CARDINAL ← 0,
nBackArcs: CARDINAL ← 0,
printSeqNumb: CARDINAL ← 0,
rib: BOOLEAN ← FALSE,
next: PGNode ← NIL
];
NullOpInstallationRelease: PROCEDURE[OpDescriptor, PGNode] = {NULL};
NullOpGetDummyOpShape: PROCEDURE[OpDescriptor] RETURNS[nArgs, nResults: CARDINAL] = {ERROR};
ArcNumberNames: ARRAY ArcNumber OF Rope.ROPE ← ["first", "second"];
TooFar: PUBLIC SIGNAL = CODE;
-- dummy node table oriented code
CreateDummyTableEntry: PROCEDURE[table: DummyNodesTable, node: PGNode] RETURNS[--index-- CARDINAL] =
BEGIN
index: CARDINAL;
IF table.nNodes = table.nodes.MaxNNodes THEN ERROR;
table.nodes[table.nNodes] ← node;
index ← table.nNodes;
table.nNodes ← table.nNodes+1;
RETURN[index];
END;
CheckDummyTableEntry: PROCEDURE[table: DummyNodesTable, node: PGNode, index: CARDINAL] =
BEGIN
IF index >= table.nNodes THEN ERROR;
IF table.nodes[index] # node THEN ERROR;
END;
ReleaseDummyTableEntry: PROCEDURE[table: DummyNodesTable, node: PGNode, index: CARDINAL] =
BEGIN
CheckDummyTableEntry[table, node, index];
table.nNodes ← table.nNodes-1;
table.nodes[index] ← table.nodes[table.nNodes];
NoteNewDummyOpNodeIndex[table.nodes[index], index];
END;
GetRandomDummyTableEntry: PUBLIC PROCEDURE[table: DummyNodesTable, random: CARDINAL] RETURNS[PGNode] =
{RETURN[table.nodes[random MOD table.nNodes]]};
GetDummyTableSize: PUBLIC PROCEDURE[table: DummyNodesTable] RETURNS[CARDINAL] =
{RETURN[table.nNodes]};
--- type checking code
pass: CARDINAL ← 0;
BeginTypeCheck: PUBLIC ENTRY PROCEDURE[node: PGNode] =
BEGIN
ENABLE UNWIND => NULL;
thisPass: CARDINAL ← pass ← pass+1;
TypeCheckGraphReachableFromANode[node, thisPass];
END;
TypeCheckGraphReachableFromANode: PROCEDURE[node: PGNode, thisPass: CARDINAL] =
BEGIN
IF node.typeCheckPass = thisPass THEN RETURN;
node.typeCheckPass ← thisPass;
node.op.kind.typeCheck[node.op, node];
FOR n: ArcNumber IN ArcNumber DO
IF node.arcs[n] # NIL THEN TypeCheckGraphReachableFromANode[node.arcs[n], thisPass];
ENDLOOP;
END;
TypeCheckBase: PROCEDURE[node: PGNode, arc: ArcNumber, nArgs, nResults: CARDINAL, skipResultVar: CARDINAL] =
BEGIN
target: PGNode ← node.arcs[arc];
IF target = NIL THEN ERROR;
StackBaseCheck[node.stackState, target.stackState, nArgs, nResults];
FrameVarsCheck[node.frameVarsState, target.frameVarsState, skipResultVar];
END;
BasicNodeTypeCheck: PUBLIC PROCEDURE[node: PGNode, nArgs, nResults: CARDINAL, skipResultVar: CARDINAL ← LAST[CARDINAL], twoArcs: BOOLEAN ← FALSE, jump: BOOLEAN ← FALSE] =
BEGIN
IF nArgs = 0 AND nResults = 1 AND GetLength[node.arcs[first].frameVarsState] = GetLength[node.frameVarsState] + 1 AND skipResultVar = LAST[CARDINAL] AND NOT twoArcs THEN -- we are in the special case of pushing onto the local variables
BEGIN
nResults ← 0;
skipResultVar ← GetLength[node.frameVarsState];
END;
IF jump THEN
BEGIN
IF node.arcs[first] # NIL THEN ERROR;
TypeCheckBase[node, second, nArgs, nResults, skipResultVar];
END
ELSE IF twoArcs THEN
BEGIN
TypeCheckBase[node, first, nArgs, nResults, skipResultVar];
TypeCheckBase[node, second, nArgs, nResults, skipResultVar];
END
ELSE
BEGIN
TypeCheckBase[node, first, nArgs, nResults, skipResultVar];
IF node.arcs[second] # NIL THEN ERROR;
END;
FOR arc: ArcNumber IN (second..LAST[ArcNumber]] DO
IF node.arcs[arc] # NIL THEN ERROR;
ENDLOOP;
IF node.arcs[first] # NIL AND node.arcs[first] = node.procedureInfo.entryNode THEN ERROR;
IF node.arcs[second] # NIL AND node.arcs[second] = node.procedureInfo.entryNode THEN ERROR;
IF node.procedureInfo.linearized AND node.arcs[first] # NIL AND node.arcs[first] # node.next THEN ERROR;
END;
TypeCheckEPNode: PUBLIC PROCEDURE[node: PGNode, nArgs: CARDINAL] =
BEGIN
next: PGNode ← node.arcs[first];
IF node.procedureInfo.entryNode # node THEN ERROR;
IF nArgs # GetLength[node.procedureInfo.allowedArgs] THEN ERROR;
IF node.frameVarsState # NIL THEN ERROR;
IF node.stackState # NIL THEN ERROR;
FOR I: CARDINAL IN [0..GetLength[node.procedureInfo.allowedArgs]) DO
IF NOT WordStorableAs[
GetWordTypeFromOffset[node.procedureInfo.allowedArgs, I],
GetWordTypeFromOffset[next.frameVarsState, I]] THEN ERROR;
ENDLOOP;
FOR I: CARDINAL IN [GetLength[node.procedureInfo.allowedArgs]..GetLength[next.frameVarsState]) DO
IF GetWordTypeFromOffset[next.frameVarsState, I].type # uninitialized THEN ERROR;
ENDLOOP;
IF next.stackState # NIL AND GetLength[next.stackState] # 0 THEN ERROR;
FOR arc: ArcNumber IN (second..LAST[ArcNumber]] DO
IF node.arcs[arc] # NIL THEN ERROR;
ENDLOOP;
END;
TypeCheckRETNode: PUBLIC PROCEDURE[node: PGNode, nResults: CARDINAL] =
BEGIN
IF nResults # GetLength[node.procedureInfo.possibleResults] THEN ERROR;
FOR I: CARDINAL IN [0..nResults) DO
IF NOT WordStorableAs[
GetWordTypeFromOffset[node.frameVarsState, I],
GetWordTypeFromOffset[node.procedureInfo.possibleResults, I]] THEN ERROR;
ENDLOOP;
FOR arc: ArcNumber IN ArcNumber DO
IF node.arcs[arc] # NIL THEN ERROR;
ENDLOOP;
END;
CheckRelativeJump: PUBLIC PROCEDURE[node: PGNode, relativeJumpBytes: INT] =
BEGIN
IF node.arcs[second] # NIL AND node.arcs[second].relativeAddress # (node.relativeAddress + relativeJumpBytes) THEN ERROR;
END;
-- dummy node procedures
RecordDummyOpNode: PROCEDURE[node: PGNode] =
{node.dummyTableIndex ← CreateDummyTableEntry[node.procedureInfo.dummyNodesTable, node]};
CheckDummyOpNodeEntry: PROCEDURE[node: PGNode] =
{CheckDummyTableEntry[node.procedureInfo.dummyNodesTable, node, node.dummyTableIndex]};
ReleaseDummyOpNodeEntry: PROCEDURE[node: PGNode] =
{ReleaseDummyTableEntry[node.procedureInfo.dummyNodesTable, node, node.dummyTableIndex]};
NoteNewDummyOpNodeIndex: PROCEDURE[node: PGNode, index: CARDINAL] =
{node.dummyTableIndex ← index};
PrintDummyNodeDetails: PROCEDURE[node: PGNode, on: IO.STREAM, nested: CARDINAL] =
BEGIN
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["(%g, %g)\N", IO.card[LOOPHOLE[node.procedureInfo.procedure, LONG CARDINAL]], IO.card[node.dummyTableIndex]];
END;
-- final procedures for linearizing and binary output
AssignRelativeGraphNodeAddresses: PUBLIC PROCEDURE[node: PGNode, GetJBOpForJump: PROCEDURE[deltaBytes: INTEGER] RETURNS[OpDescriptor], GetJDBOpForJump: PROCEDURE[deltaBytes: INTEGER] RETURNS[OpDescriptor]] RETURNS[size: INT] =
-- may have to install some extra jumps, or modify some conditional jumps
-- assumes that the graph is already print sorted
BEGIN
relativeAddress: INT ← 0;
modified: BOOLEAN ← TRUE;
-- first pass
FOR n: PGNode ← node, n.next WHILE n # NIL DO
IF n.arcs[first] # NIL AND n.arcs[first] # n.next THEN LinearizeNode[n, GetJBOpForJump];
n.relativeAddress ← relativeAddress;
relativeAddress ← relativeAddress + n.op.kind.GetSize[n.op];
ENDLOOP;
-- now handle jumps that are too far to fit in a byte field
WHILE modified DO
modified ← FALSE;
relativeAddress ← 0;
FOR n: PGNode ← node, n.next WHILE n # NIL DO
IF n.arcs[second] # NIL THEN
n.op.kind.SetRelativeJump[n.op, n.arcs[second].relativeAddress - n.relativeAddress
! TooFar =>
BEGIN
modified ← TRUE;
InstallLongJump[n, GetJBOpForJump, GetJDBOpForJump];
-- the relative address will get set on next pass
CONTINUE;
END];
IF n.relativeAddress # relativeAddress THEN
BEGIN
n.relativeAddress ← relativeAddress;
modified ← TRUE;
END;
relativeAddress ← relativeAddress + n.op.kind.GetSize[n.op];
ENDLOOP;
ENDLOOP;
RETURN[relativeAddress];
END;
TearDownGraph: PUBLIC PROCEDURE[node: PGNode] =
BEGIN
next: PGNode;
FOR n: PGNode ← node, next WHILE next # NIL DO
next ← n.next;
node.frameVarsState ← NIL;
node.stackState ← NIL;
node.op ← NIL;
node.arcs ← [NIL, NIL];
node.procedureInfo ← NIL;
node.next ← NIL
ENDLOOP;
END;
-- new, basic graph modification procedures
CreateProcedureGraph: PUBLIC PROCEDURE[
allowedArgs, frameExtension, possibleResults: SeqType,
typeSet: TypeSet,
random: PROCEDURE RETURNS[CARDINAL],
getEPOpForEntry: PROCEDURE[nArgs: CARDINAL] RETURNS[OpDescriptor],
getDragonOp: PROCEDURE[
class: OpTypeClass,
random: PROCEDURE RETURNS[CARDINAL],
selectLocalIndex: PROCEDURE RETURNS[CARDINAL],
selectRemoteIndex: PROCEDURE RETURNS[CARDINAL],
selectLocalRemoteIndices: PROCEDURE RETURNS[l,r: CARDINAL]]
RETURNS[OpDescriptor],
getRetOpForReturn: PROCEDURE[nRetWords: CARDINAL] RETURNS[OpDescriptor]]
RETURNS[
procedureInfo: ProcedureInfo]
=
BEGIN
array: REF DummyNodesTableArray ← NEW[DummyNodesTableArray[100]];
table: DummyNodesTable ← NEW[DummyNodesTableBody ← [0, array]];
extensionLength: CARDINAL ← GetLength[frameExtension];
entryNode: PGNode ← BuildANewNode[NIL, NIL, NIL];
tailNode: PGNode;
initialFrameVars: SeqType ← CopySeqType[allowedArgs];
initialStack: SeqType ← CreateSeqType[typeSet, NIL, 0];
procedureInfo ← NEW[ProcedureInfoBody ← [
NIL, allowedArgs, possibleResults, table, FALSE, typeSet, entryNode, FALSE, FALSE]];
entryNode.procedureInfo ← procedureInfo;
-- fix up the entry node
tailNode ← InstallAnOpAndAppendNextNode[entryNode, getEPOpForEntry[GetLength[allowedArgs]], 0, NIL];
tailNode.frameVarsState ← initialFrameVars;
-- initialize the frame extension, by "pushing" the initial values
FOR I: CARDINAL IN [0..GetLength[frameExtension]) DO
type: WordType ← GetWordTypeFromOffset[frameExtension, I];
local, remote: CARDINAL;
op: OpDescriptor;
selectLocal: PROCEDURE RETURNS[CARDINAL] = {RETURN[local]};
selectLocalRemote: PROCEDURE RETURNS[CARDINAL, CARDINAL] = {RETURN[local, remote]};
local ← GetLocalOffset[initialFrameVars, type, random[]];
IF local # LAST[CARDINAL] THEN
{IF (op ← getDragonOp[PushT, random, selectLocal, NIL, NIL]) = NIL THEN ERROR}
ELSE
BEGIN
[local, remote] ← GetRemoteOffset[initialFrameVars, type, random[]];
IF local = LAST[CARDINAL] THEN ERROR;
IF (op ← getDragonOp[PushFIT, random, NIL, NIL, selectLocalRemote]) = NIL THEN ERROR;
END;
tailNode ← InstallAnOpAndAppendNextNode[tailNode, op, 0, NIL, LAST[CARDINAL], type];
IF GetTypeSetOfSeq[tailNode.frameVarsState] = NIL THEN ERROR;
ENDLOOP;
-- push the results on the stack
BEGIN
targetNode: PGNode ← BuildANewNode[tailNode.frameVarsState, possibleResults, procedureInfo];
IF tailNode.stackState = NIL THEN tailNode.stackState ← CreateSeqType[GetTypeSetOfSeq[tailNode.frameVarsState], NIL, 0];
CreateDummyOpArc[tailNode, targetNode];
tailNode ← targetNode;
END;
-- finally, store the results
FOR I: CARDINAL DECREASING IN [0..GetLength[possibleResults]) DO
type: WordType ← GetWordTypeFromOffset[possibleResults, I];
LocalIndex: PROCEDURE RETURNS[CARDINAL] = {RETURN[I]};
op: OpDescriptor;
IF type # TopTwoOfSeq[tailNode.stackState].s0 THEN ERROR;
op ← getDragonOp[StoreLocalT, random, LocalIndex, NIL, NIL];
IF op = NIL THEN ERROR;
tailNode ← InstallAnOpAndAppendNextNode[tailNode, op, 1, NIL, I, type];
ENDLOOP;
-- lastly, install the return op code
tailNode.op ← getRetOpForReturn[GetLength[possibleResults]];
END;
BuildANewNode: PUBLIC PROCEDURE[frameVarsType, stackType: SeqType, procedureInfo: ProcedureInfo] RETURNS[PGNode] =
BEGIN
newNode: PGNode ← NEW[PGNodeBody];
newNode.frameVarsState ← CopySeqType[frameVarsType];
newNode.stackState ← CopySeqType[stackType];
newNode.procedureInfo ← procedureInfo;
RETURN[newNode];
END;
InstallAnOp: PROCEDURE[node: PGNode, op: OpDescriptor, targetOne, targetTwo: PGNode ← NIL] =
BEGIN
IF node.op # NIL THEN
BEGIN
node.op.kind.Release[node.op, node];
END;
node.op ← op;
node.arcs ← [targetOne, targetTwo];
op.kind.NoteInstallation[op, node];
END;
InstallAnOpAndAppendNextNode: PROCEDURE[node: PGNode, op: OpDescriptor, nArgs: CARDINAL, possibleResult: WordType, possibleChangeLocal: CARDINAL ← LAST[CARDINAL], possibleNewLocalType: WordType ← NIL] RETURNS[PGNode] =
BEGIN
newStack, newFrameState: SeqType;
newNode: PGNode;
IF node.op # NIL THEN ERROR;
FOR i: ArcNumber IN ArcNumber DO IF node.arcs[i] # NIL THEN ERROR ENDLOOP;
newStack ← PopSomeTypes[node.stackState, nArgs];
IF possibleResult # NIL THEN newStack ← PushOneType[newStack, possibleResult];
newFrameState ← IF possibleNewLocalType = NIL THEN CopySeqType[node.frameVarsState]
ELSE IF possibleChangeLocal = LAST[CARDINAL] THEN
PushOneType[node.frameVarsState, possibleNewLocalType]
ELSE CopyWithOneTypeChanged[node.frameVarsState, possibleChangeLocal, possibleNewLocalType];
newNode ← BuildANewNode[newFrameState, newStack, node.procedureInfo];
InstallAnOp[node, op, newNode, NIL];
RETURN[newNode];
END;
CreateDummyOpArc: PROCEDURE[sourceNode, targetNode: PGNode] =
BEGIN
op: OpDescriptor ← CreateDummyOp[sourceNode.stackState, targetNode.stackState];
InstallAnOp[sourceNode, op, targetNode];
END;
GetDummyNodeOpShape: PUBLIC PROCEDURE[node: PGNode] RETURNS[nArgs, nResults: CARDINAL] =
{[nArgs, nResults] ← node.op.kind.GetDummyOpShape[node.op]};
GetStack: PUBLIC PROCEDURE[node: PGNode] RETURNS[SeqType] =
{RETURN[node.stackState]};
GetNextStack: PUBLIC PROCEDURE[node: PGNode] RETURNS[SeqType] =
{RETURN[node.arcs[first].stackState]};
GetTopOfStack: PUBLIC PROCEDURE[node: PGNode] RETURNS[WordType] =
{RETURN[TopTwoOfSeq[node.stackState].s0]};
GetTopOfNextStack: PUBLIC PROCEDURE[node: PGNode] RETURNS[WordType] =
BEGIN
IF (node.arcs[first].stackState = NIL OR GetLength[node.arcs[first].stackState] = 0) AND GetLength[node.arcs[first].frameVarsState] = GetLength[node.frameVarsState]+1 THEN -- we are in the special case of pushing onto the local frame vars
RETURN[TopTwoOfSeq[node.arcs[first].frameVarsState].s0]
ELSE RETURN[TopTwoOfSeq[node.arcs[first].stackState].s0]
END;
GetNextOfStack: PUBLIC PROCEDURE[node: PGNode] RETURNS[WordType] =
{RETURN[TopTwoOfSeq[node.stackState].s1]};
GetNextOfNextStack: PUBLIC PROCEDURE[node: PGNode] RETURNS[WordType] =
{RETURN[TopTwoOfSeq[node.arcs[first].stackState].s1]};
GetFrameVarType: PUBLIC PROCEDURE[node: PGNode, varOffset: CARDINAL] RETURNS[WordType] =
{RETURN[GetWordTypeFromOffset[node.frameVarsState, varOffset]]};
GetNextFrameVarType: PUBLIC PROCEDURE[node: PGNode, varOffset: CARDINAL] RETURNS[WordType] =
{RETURN[GetWordTypeFromOffset[node.arcs[first].frameVarsState, varOffset]]};
GetTypeSet: PUBLIC PROCEDURE[node: PGNode] RETURNS[TypeSet] =
{RETURN[node.procedureInfo.typeSet]};
LinearizeNode: PROCEDURE[n: PGNode, GetJBOpForJump: PROCEDURE[deltaBytes: INTEGER] RETURNS[OpDescriptor]] =
BEGIN
jumpNode: PGNode ← BuildANewNode[n.arcs[first].frameVarsState, n.arcs[first].stackState, n.procedureInfo];
InstallAnOp[jumpNode, GetJBOpForJump[0], NIL, n.arcs[first]];
n.arcs[first] ← jumpNode;
jumpNode.next ← n.next;
n.next ← jumpNode;
END;
InstallLongJump: PROCEDURE[n: PGNode, GetJBOpForJump, GetJDBOpForJump: PROCEDURE[deltaBytes: INTEGER] RETURNS[OpDescriptor]] =
BEGIN
SELECT n.arcs[first] FROM
= NIL =>
BEGIN
-- the current op must be JB, but we don't have a way to check that
next: PGNode ← n.next;
InstallAnOp[n, GetJDBOpForJump[0], NIL, n.arcs[second]];
n.next ← next;
END;
# NIL =>
BEGIN
-- we use a dumb solution, later we can add code to try for a better one involving changing the mode of the op
next: PGNode ← n.next;
shortJumpNode: PGNode ← BuildANewNode[n.arcs[first].frameVarsState, n.arcs[first].stackState, n.procedureInfo];
longJumpNode: PGNode ← BuildANewNode[n.arcs[second].frameVarsState, n.arcs[second].stackState, n.procedureInfo];
InstallAnOp[longJumpNode, GetJDBOpForJump[0], NIL, n.arcs[second]];
longJumpNode.next ← next;
InstallAnOp[shortJumpNode, GetJBOpForJump[0], NIL, n.arcs[first]];
shortJumpNode.next ← longJumpNode;
n.arcs[first] ← shortJumpNode;
n.arcs[second] ← longJumpNode;
n.next ← shortJumpNode;
END;
ENDCASE => ERROR;
END;
-- graph modification procedures
SplitADummyArc: PUBLIC PROCEDURE[source: PGNode, copySomeOfOpSource: BOOLEAN, amountOfCopy: CARDINAL, extension: SeqType] =
BEGIN
intermediateStackType: SeqType ← CreateIntermediateType[source, copySomeOfOpSource, amountOfCopy, extension];
newNode: PGNode ← BuildANewNode[source.frameVarsState, intermediateStackType, source.procedureInfo];
CreateDummyOpArc[newNode, source.arcs[first]];
CreateDummyOpArc[source, newNode];
END;
InsertTestA: PUBLIC PROCEDURE[source: PGNode, op: OpDescriptor, loop: BOOLEAN] =
BEGIN
typeSet: TypeSet ← GetTypeSetOfSeq[source.frameVarsState];
additionalArg: SeqType;
testNodeStackState: SeqType;
bodyABNodeStackStates: SeqType;
bodyANode: PGNode;
bodyBNode: PGNode;
testNode: PGNode;
GenOrdinaryWordType: PROCEDURE[i: CARDINAL] RETURNS[WordType] =
{RETURN[GetOrdinaryWordType[typeSet]]};
-- build the new stack states
additionalArg ← CreateSeqType[typeSet, NIL, 1];
FillSeqType[additionalArg, GenOrdinaryWordType];
testNodeStackState ← MergeTypes[source.stackState, additionalArg];
bodyABNodeStackStates ← SubtractAddTypes[testNodeStackState, additionalArg, NIL];
-- prepare bodyANode
bodyANode ← BuildANewNode[source.frameVarsState, bodyABNodeStackStates, source.procedureInfo];
-- prepare bodyBNode
bodyBNode ← BuildANewNode[source.frameVarsState, bodyABNodeStackStates, source.procedureInfo];
CreateDummyOpArc[bodyBNode, source.arcs[first]];
-- prepare test node
testNode ← BuildANewNode[source.frameVarsState, testNodeStackState, source.procedureInfo];
InstallAnOp[testNode, op, bodyANode, bodyBNode];
-- finally
CreateDummyOpArc[bodyANode, IF loop THEN testNode ELSE source.arcs[first]];
-- last arc is built here so that test node is built before the arc if a loop being built
CreateDummyOpArc[source, testNode];
END;
InsertSourceReduction: PUBLIC PROCEDURE[source: PGNode, selectOp: PROCEDURE[dummyOp: OpDescriptor, locals: SeqType, ordinaryWordType: WordType] RETURNS[OpDescriptor, CARDINAL]] =
BEGIN
op: OpDescriptor;
nPop: CARDINAL;
intermediateNode: PGNode;
[op, nPop] ← selectOp[source.op, source.frameVarsState, GetOrdinaryWordType[source.procedureInfo.typeSet]];
IF op = NIL THEN RETURN;
intermediateNode ← BuildANewNode[source.frameVarsState, PopSomeTypes[source.stackState, nPop], source.procedureInfo];
CreateDummyOpArc[intermediateNode, source.arcs[first]];
InstallAnOp[source, op, intermediateNode];
END;
InsertTargetReduction: PUBLIC PROCEDURE[source: PGNode, selectOp: PROCEDURE[dummyOp: OpDescriptor, locals: SeqType, ordinaryWordType: WordType] RETURNS[OpDescriptor, CARDINAL]] =
BEGIN
op: OpDescriptor;
nPush: CARDINAL;
intermediateNode: PGNode;
[op, nPush] ← selectOp[source.op, source.frameVarsState, GetOrdinaryWordType[source.procedureInfo.typeSet]];
IF op = NIL THEN RETURN;
intermediateNode ← BuildANewNode[source.frameVarsState, PopSomeTypes[source.arcs[first].stackState, nPush], source.procedureInfo];
InstallAnOp[intermediateNode, op, source.arcs[first]];
CreateDummyOpArc[source, intermediateNode];
END;
InsertSFCallInDummyArc: PUBLIC PROCEDURE[source: PGNode, op: OpDescriptor, procType: WordType] =
BEGIN
opArgs, opRets: SeqType;
prePreCallStackType: SeqType;
preCallStackType: SeqType;
postCallStackType: SeqType;
callNode, retNode: PGNode;
-- compute new stack types
[opArgs, opRets] ← GetArgsResultsOfProcedureType[procType];
prePreCallStackType ← MergeTypes[source.stackState, opArgs];
preCallStackType ← PushOneType[prePreCallStackType, procType];
postCallStackType ← SubtractAddTypes[prePreCallStackType, opArgs, NIL];
-- prepare return node
retNode ← BuildANewNode[source.frameVarsState, postCallStackType, source.procedureInfo];
CreateDummyOpArc[retNode, source.arcs[first]];
-- prepare call node
callNode ← BuildANewNode[source.frameVarsState, preCallStackType, source.procedureInfo];
InstallAnOp[callNode, op, retNode, NIL];
-- finally
CreateDummyOpArc[source, callNode];
END;
RemoveNullDummy: PUBLIC PROCEDURE[source: PGNode] =
BEGIN
nArgs, nResults: CARDINAL;
old: PGNode ← source.arcs[first];
[nArgs, nResults] ← source.op.kind.GetDummyOpShape[source.op];
IF nArgs # 0 OR nResults # 0 THEN ERROR;
InstallAnOp[source, old.op.kind.Copy[old.op], old.arcs[first], old.arcs[second]];
END;
-- some type manipulations
CreateIntermediateType: PROCEDURE[source: PGNode, copySomeOfOpSource: BOOLEAN, amountOfCopy: CARDINAL, extension: SeqType] RETURNS[SeqType] =
BEGIN
sourceOpData: REF DummyOpDataBody ← NARROW[source.op.data];
model: SeqType ← IF copySomeOfOpSource THEN source.stackState ELSE source.arcs[first].stackState;
baseSize: CARDINAL ← GetLength[source.stackState] - GetLength[sourceOpData.allowedArgs];
reducedCopy: CARDINAL ← MIN[amountOfCopy, GetLength[model]-baseSize];
out: SeqType ← CreateTypeExtendingPartOfType[model, baseSize+reducedCopy, extension];
RETURN[out];
END;
-- code for sorting nodes and printing
-- this procedure assumes that PrintSortGraph has previously been called.
PrintGraph: PUBLIC PROCEDURE[title: Rope.ROPE, node: PGNode, on: IO.STREAM] =
BEGIN
seqNumber: CARDINAL ← 0;
on.PutF["\N\N\N%g\N\N", IO.rope[title]];
FOR n: PGNode ← node, n.next WHILE n # NIL DO
{n.printSeqNumb ← seqNumber ← seqNumber+1}
ENDLOOP;
FOR n: PGNode ← node, n.next WHILE n # NIL DO
PrintOneGraphNode[n, on]
ENDLOOP;
END;
-- PrintSortGraph: This procedure sorts that portion of the program graph which is reachable from the given node. The result is that the "next" field at each node is arranged to point to the next node in the sort order. The resulting order is a "print order". First, all "backward" arcs are identified, thus finding a tree which covers the graph. The print order is determined such that a given node will be "visited" only after all nodes from which it can be reached (by "forward" arcs) have already been visited. Otherwise, nodes which can be visited by "first" arcs will be visited before nodes that require following "second" arcs, etc. Uses an incremented value of the (global) variable sortScanNumb to distinguish visits of this sort call from those of previous calls.
PrintSortGraph: PUBLIC ENTRY PROCEDURE[node: PGNode] =
BEGIN
thisPass: CARDINAL ← sortScanNumb + 1;
last: PGNode;
sortScanNumb ← thisPass;
FirstSortVisit[node, thisPass];
last ← SecondSortVisit[node, thisPass, NIL];
last.next ← NIL;
END;
sortScanNumb: CARDINAL ← 0;
-- NOTE: following sort procedures would have a simpler form if they were purely recursive, but we try to avoid a recursion for each node that only has a single outgoing pointer, which is its first pointer and which is not a backward pointer.
-- FirstSortVisit: marks all "backward" arcs, and also leaves in each node a count of the number of forward arcs pointing to the node. Touches only those nodes reachable from start. There had better be no other incarnation of this procedure running on the same graph at the same time.
FirstSortVisit: PROCEDURE[firstNode: PGNode, scanNumb: CARDINAL] =
BEGIN
node: PGNode ← firstNode;
lastNode: PGNode;
DO
ok: BOOLEAN ← TRUE; -- tentative
node.scanNumb ← scanNumb;
node.rib ← TRUE;
node.nFwdArcs ← 1;
node.nBackArcs ← 0;
IF node.arcs[first] = NIL THEN ok ← FALSE;
FOR i: ArcNumber IN (FIRST[ArcNumber]..LAST[ArcNumber]]
DO IF node.arcs[i] # NIL THEN ok ← FALSE ENDLOOP;
-- in the following code we advance one node and loop
IF ok AND node.arcs[first].scanNumb # scanNumb THEN
BEGIN
node.backArcs[first] ← FALSE;
node ← node.arcs[first];
LOOP;
END;
-- in the following code we handle the case of more than one out pointer, or first pointer = NIL
FOR i: ArcNumber IN ArcNumber DO
IF node.arcs[i] # NIL AND node.arcs[i].scanNumb = scanNumb THEN
BEGIN -- this node has been visited
IF node.arcs[i].rib THEN
BEGIN -- we have a back pointer in hand
node.arcs[i].nBackArcs ← node.arcs[i].nBackArcs + 1;
node.backArcs[i] ← TRUE;
END
ELSE
BEGIN -- we have a forward pointer in hand
node.arcs[i].nFwdArcs ← node.arcs[i].nFwdArcs + 1;
node.backArcs[i] ← FALSE;
END
END
ELSE IF node.arcs[i] # NIL THEN
BEGIN -- this node has not been visited
node.backArcs[i] ← FALSE;
FirstSortVisit[node.arcs[i], scanNumb];
END;
ENDLOOP;
lastNode ← node;
EXIT;
ENDLOOP;
-- now lets remove the rib marking
node ← firstNode;
DO
node.rib ← FALSE;
IF node = lastNode THEN EXIT;
node ← node.arcs[first];
ENDLOOP;
END;
-- SecondSortVisit: this procedure plants the next pointers in print sort order
SecondSortVisit: PROCEDURE[firstNode: PGNode, scanNumb: CARDINAL, previous: PGNode] RETURNS[last: PGNode] =
BEGIN
node: PGNode ← firstNode;
DO
ok: BOOLEAN ← TRUE; -- tentative
IF node.arcs[first] = NIL THEN ok ← FALSE;
IF node.backArcs[first] THEN ok ← FALSE;
IF ok AND node.arcs[first].nFwdArcs # 1 THEN ok ← FALSE;
FOR i: ArcNumber IN (FIRST[ArcNumber]..LAST[ArcNumber]]
DO IF node.arcs[i] # NIL THEN ok ← FALSE ENDLOOP;
-- visit this node
IF node.scanNumb # scanNumb THEN ERROR;
IF previous # NIL THEN previous.next ← node;
last ← node;
IF ok THEN
BEGIN -- step along a simple chain
node.arcs[first].nFwdArcs ← node.arcs[first].nFwdArcs-1;
IF node.arcs[first].nFwdArcs # 0 THEN ERROR;
previous ← node;
node ← node.arcs[first];
LOOP;
END
ELSE -- not the ok case, not a simple chain advance
BEGIN
FOR i: ArcNumber IN ArcNumber DO
IF NOT node.backArcs[i] AND node.arcs[i] # NIL THEN
BEGIN
node.arcs[i].nFwdArcs ← node.arcs[i].nFwdArcs - 1;
IF node.arcs[i].nFwdArcs = 0 THEN
BEGIN
last ← SecondSortVisit[node.arcs[i], scanNumb, last];
END;
END;
ENDLOOP;
RETURN[last];
END;
ENDLOOP;
END;
PrintOneGraphNode: PROCEDURE[node: PGNode, on: IO.STREAM] =
BEGIN
-- print node title
on.PutF["%g [%g]\N", IO.card[node.printSeqNumb], IO.int[node.relativeAddress]];
-- print initial stack state
on.PutF["stack state: "];
PrintSeqType[node.stackState, on];
on.PutF["\N"];
-- print operation
PrintOpDescriptor[node.op, node, on, 4];
-- print outgoing arcs
IF node.arcs[first] = NIL THEN
on.PutF[" %g: %g\N", IO.rope[ArcNumberNames[first]], IO.rope["NIL"]];
IF node.arcs[first] # NIL AND node.arcs[first].printSeqNumb # node.printSeqNumb+1 THEN
on.PutF[" %g: %g\N", IO.rope[ArcNumberNames[first]], IO.card[node.arcs[first].printSeqNumb]];
IF node.arcs[first] # NIL AND node.arcs[first].printSeqNumb = node.printSeqNumb+1 THEN
BEGIN
printFirst: BOOLEAN ← FALSE; -- tentative
FOR i: ArcNumber IN (FIRST[ArcNumber]..LAST[ArcNumber]] DO
IF node.arcs[i] # NIL THEN {printFirst ← TRUE; EXIT}
ENDLOOP;
IF printFirst THEN on.PutF[" %g: %g\N", IO.rope[ArcNumberNames[first]], IO.card[node.arcs[first].printSeqNumb]];
END;
FOR i: ArcNumber IN (FIRST[ArcNumber]..LAST[ArcNumber]] DO
IF node.arcs[i] # NIL THEN
on.PutF[" %g: %g\N", IO.rope[ArcNumberNames[i]], IO.card[node.arcs[i].printSeqNumb]];
ENDLOOP;
on.PutF["\N"];
END;
PrintOpDescriptor: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
BEGIN
IF op = NIL THEN
BEGIN
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["NIL op\N"];
END
ELSE
BEGIN
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["%g\N", IO.rope[op.kind.name]];
op.kind.printDetails[op, node, on, nested+4];
END;
END;
-- byte generation
GenGraphBytes: PUBLIC PROCEDURE[node: PGNode, oneByte: PROC[[0..255]]] =
BEGIN
FOR n: PGNode ← node, n.next WHILE n # NIL DO
GenBytesForOneGraphNode[n, oneByte]
ENDLOOP;
END;
GenBytesForOneGraphNode: PROCEDURE[node: PGNode, oneByte: PROC[[0..255]]] =
{GenBytesForOpDescriptor[node.op, oneByte]};
GenBytesForOpDescriptor: PROCEDURE[op: OpDescriptor, oneByte: PROC[[0..255]]] =
{op.kind.genBytes[op, oneByte]};
--
-- what follows is specific to various op types
--
-- Dummy Op
DummyOpKind: OpKind ← NEW[OpKindBody ← [
"dummyOp",
CopyDummyOp,
NoteDummyOpInstallation,
ReleaseDummyOp,
GetDummyOpShape,
NIL,
NIL,
TypeCheckDummyOp,
PrintDummyOpDetails]];
DummyOpDataBody: TYPE = RECORD[
allowedArgs: SeqType ← NIL,
possibleResults: SeqType ← NIL
];
CopyDummyOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF DummyOpDataBody ← NARROW[op.data];
outData: REF DummyOpDataBody ← NEW[DummyOpDataBody];
outOp: OpDescriptor ← NEW[OpDescriptorBody ← [DummyOpKind, outData]];
outData.allowedArgs ← CopySeqType[inData.allowedArgs];
outData.possibleResults ← CopySeqType[inData.possibleResults];
RETURN[outOp];
END;
CreateDummyOp: PROCEDURE[source, target: SeqType] RETURNS[OpDescriptor] =
BEGIN
baseSize: CARDINAL;
data: REF DummyOpDataBody ← NEW[DummyOpDataBody];
op: OpDescriptor ← NEW[OpDescriptorBody ← [DummyOpKind, data]];
args: SeqType;
results: SeqType;
-- determine appropriate base
baseSize ← FindFirstDiff[source, target];
-- build the dummy op
args ← TopOfSeq[source, baseSize];
results ← TopOfSeq[target, baseSize];
data.allowedArgs ← args;
data.possibleResults ← results;
RETURN[op]
END;
NoteDummyOpInstallation: PROCEDURE[op: OpDescriptor, node: PGNode] =
{RecordDummyOpNode[node]};
ReleaseDummyOp: PROCEDURE[op: OpDescriptor, node: PGNode] =
{ReleaseDummyOpNodeEntry[node]};
GetDummyOpShape: PROCEDURE[op: OpDescriptor] RETURNS[nArgs, nResults: CARDINAL] =
BEGIN
data: REF DummyOpDataBody ← NARROW[op.data];
RETURN[GetLength[data.allowedArgs], GetLength[data.possibleResults]];
END;
TypeCheckDummyOp: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF DummyOpDataBody ← NARROW[op.data];
BasicNodeTypeCheck[node, GetLength[opData.allowedArgs], GetLength[opData.possibleResults]];
CheckDummyOpNodeEntry[node];
ArgSeqTypeCheck[node.stackState, opData.allowedArgs];
ResultSeqTypeCheck[opData.possibleResults, node.arcs[first].stackState];
END;
PrintDummyOpDetails: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
BEGIN
opData: REF DummyOpDataBody ← NARROW[op.data];
PrintDummyNodeDetails[node, on, nested];
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["args : "]; PrintSeqType[opData.allowedArgs, on]; on.PutF["\N"];
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["results: "]; PrintSeqType[opData.possibleResults, on]; on.PutF["\N"];
END;
TopTwoArgsOfDummyOp: PUBLIC PROCEDURE[dummyOp: OpDescriptor] RETURNS[s0, s1: WordType] =
BEGIN
opData: REF DummyOpDataBody ← NARROW[dummyOp.data];
[s0, s1] ← TopTwoOfSeq[opData.allowedArgs];
END;
TopResultOfDummyOp: PUBLIC PROCEDURE[dummyOp: OpDescriptor] RETURNS[t0: WordType] =
BEGIN
opData: REF DummyOpDataBody ← NARROW[dummyOp.data];
[t0, ] ← TopTwoOfSeq[opData.possibleResults];
END;
-- Dummy Test Op
DummyTestOpKindDataBody: TYPE = RECORD[ordinaryWordType: WordType];
dummyTestOpKind: OpKind ← NEW[OpKindBody ← ["dummyTestOp", CopyDummyTestOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckDummyTest, PrintDummyTestOpDetails]];
CopyDummyTestOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF DummyTestOpKindDataBody ← NARROW[op.data];
outData: REF DummyTestOpKindDataBody ← NEW[DummyTestOpKindDataBody];
outOp: OpDescriptor ← NEW[OpDescriptorBody ← [dummyTestOpKind, outData]];
outData.ordinaryWordType ← inData.ordinaryWordType;
RETURN[outOp];
END;
CreateDummyTestOp: PROCEDURE[typeSet: TypeSet] RETURNS[OpDescriptor] =
BEGIN
data: REF DummyTestOpKindDataBody← NEW[DummyTestOpKindDataBody ← [GetOrdinaryWordType[typeSet]]];
RETURN[NEW[OpDescriptorBody ← [dummyTestOpKind, data]]];
END;
TypeCheckDummyTest: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF DummyTestOpKindDataBody ← NARROW[op.data];
BasicNodeTypeCheck[node, 1, 0, LAST[CARDINAL], TRUE];
ArgPairTypeCheck[node.stackState, opData.ordinaryWordType, NIL];
END;
PrintDummyTestOpDetails: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
{NULL};
-- Local ops
LocalOpKindDataBody: TYPE = RECORD[
localVar: CARDINAL];
storeLocalOpKind: OpKind ← NEW[OpKindBody ← ["storeLOp", CopyStoreLOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckStoreL, PrintLocalOpDetails]];
loadLocalOpKind: OpKind ← NEW[OpKindBody ← ["loadLOp", CopyLoadLOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckLoadL, PrintLocalOpDetails]];
CopyLoadLOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF LocalOpKindDataBody ← NARROW[op.data];
RETURN[CreateLocalOp[load, inData.localVar]];
END;
CopyStoreLOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF LocalOpKindDataBody ← NARROW[op.data];
RETURN[CreateLocalOp[store, inData.localVar]];
END;
CreateLocalOp: PUBLIC PROCEDURE[loadStore: LoadStore, localOffset: CARDINAL] RETURNS[OpDescriptor] =
BEGIN
kind: OpKind ← IF loadStore = load THEN loadLocalOpKind ELSE storeLocalOpKind;
data: REF LocalOpKindDataBody ← NEW[LocalOpKindDataBody ← [localOffset]];
RETURN[NEW[OpDescriptorBody ← [kind, data]]];
END;
TypeCheckStoreL: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF LocalOpKindDataBody ← NARROW[op.data];
BasicNodeTypeCheck[node, 1, 0, opData.localVar];
ArgPairTypeCheck[node.stackState, GetWordTypeFromOffset[node.arcs[first].frameVarsState, opData.localVar], NIL];
END;
TypeCheckLoadL: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF LocalOpKindDataBody ← NARROW[op.data];
BasicNodeTypeCheck[node, 0, 1];
ResultWordTypeCheck[GetWordTypeFromOffset[node.frameVarsState, opData.localVar], node.arcs[first].stackState];
END;
PrintLocalOpDetails: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
BEGIN
opData: REF LocalOpKindDataBody ← NARROW[op.data];
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["localVar: %g\N", IO.card[opData.localVar]];
END;
-- Indirect Ops
IndirectOpKindDataBody: TYPE = RECORD[
remoteOffset: CARDINAL];
loadIOpKind: OpKind ← NEW[OpKindBody ← ["loadIOp", CopyLoadIOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckLoadI, PrintIndirectOpDetails]];
storeIOpKind: OpKind ← NEW[OpKindBody ← ["storeIOp", CopyStoreIOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckStoreI, PrintIndirectOpDetails]];
CopyLoadIOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF IndirectOpKindDataBody ← NARROW[op.data];
RETURN[CreateIndirectOp[load, inData.remoteOffset]];
END;
CopyStoreIOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF IndirectOpKindDataBody ← NARROW[op.data];
RETURN[CreateIndirectOp[store, inData.remoteOffset]];
END;
CreateIndirectOp: PUBLIC PROCEDURE[loadStore: LoadStore, remoteOffset: CARDINAL] RETURNS[OpDescriptor] =
BEGIN
kind: OpKind ← IF loadStore = load THEN loadIOpKind ELSE storeIOpKind;
data: REF IndirectOpKindDataBody ← NEW[IndirectOpKindDataBody ← [remoteOffset]];
RETURN[NEW[OpDescriptorBody ← [kind, data]]];
END;
TypeCheckStoreI: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF IndirectOpKindDataBody ← NARROW[op.data];
s1: WordType;
BasicNodeTypeCheck[node, 2, 0];
[ , s1] ← TopTwoOfSeq[node.stackState];
StoreIndirectTypeCheck[node.stackState, s1, opData.remoteOffset];
END;
TypeCheckLoadI: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF IndirectOpKindDataBody ← NARROW[op.data];
s0: WordType;
BasicNodeTypeCheck[node, 1, 1];
[s0, ] ← TopTwoOfSeq[node.stackState];
LoadIndirectTypeCheck[s0, opData.remoteOffset, node.arcs[first].stackState];
END;
PrintIndirectOpDetails: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
BEGIN
opData: REF IndirectOpKindDataBody ← NARROW[op.data];
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["remoteOffset: %g\N", IO.card[opData.remoteOffset]];
END;
-- Local Indirect Ops
LocalIndirectOpKindDataBody: TYPE = RECORD[
localVar: CARDINAL,
remoteOffset: CARDINAL];
loadLocalIndirectOpKind: OpKind ← NEW[OpKindBody ← ["loadLI", CopyLoadLIOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckLoadLI, PrintLocalIndirectOpDetails]];
storeLocalIndirectOpKind: OpKind ← NEW[OpKindBody ← ["storeLI", CopyStoreLIOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckStoreLI, PrintLocalIndirectOpDetails]];
CopyLoadLIOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF LocalIndirectOpKindDataBody ← NARROW[op.data];
RETURN[CreateLocalIndirectOp[load, inData.localVar, inData.remoteOffset]];
END;
CopyStoreLIOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF LocalIndirectOpKindDataBody ← NARROW[op.data];
RETURN[CreateLocalIndirectOp[store, inData.localVar, inData.remoteOffset]];
END;
CreateLocalIndirectOp: PUBLIC PROCEDURE[loadStore: LoadStore, localOffset: CARDINAL, remoteOffset: CARDINAL] RETURNS[OpDescriptor] =
BEGIN
kind: OpKind ← IF loadStore = load THEN loadLocalIndirectOpKind ELSE storeLocalIndirectOpKind;
data: REF LocalIndirectOpKindDataBody ← NEW[LocalIndirectOpKindDataBody ← [localOffset, remoteOffset]];
RETURN[NEW[OpDescriptorBody ← [kind, data]]];
END;
TypeCheckLoadLI: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF LocalIndirectOpKindDataBody ← NARROW[op.data];
pointer: WordType;
BasicNodeTypeCheck[node, 0, 1];
pointer ← GetWordTypeFromOffset[node.frameVarsState, opData.localVar];
LoadIndirectTypeCheck[pointer, opData.remoteOffset, node.arcs[first].stackState];
END;
TypeCheckStoreLI: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF LocalIndirectOpKindDataBody ← NARROW[op.data];
pointer: WordType;
BasicNodeTypeCheck[node, 1, 0];
pointer ← GetWordTypeFromOffset[node.frameVarsState, opData.localVar];
StoreIndirectTypeCheck[node.stackState, pointer, opData.remoteOffset];
END;
PrintLocalIndirectOpDetails: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
BEGIN
opData: REF LocalIndirectOpKindDataBody ← NARROW[op.data];
FOR I: CARDINAL IN [0..nested) DO on.PutF[" "] ENDLOOP;
on.PutF["LocalIndirect localVar: %g, remoteOffset: %g\N", IO.card[opData.localVar], IO.card[opData.remoteOffset]];
END;
-- stack Ops
binOpKind: OpKind ← NEW[OpKindBody ← ["stackBinOp", CopyStackBinOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckStackBinOp, PrintStackOpDetails]];
popOpKind: OpKind ← NEW[OpKindBody ← ["popOp", CopyPopOp, NullOpInstallationRelease, NullOpInstallationRelease, NullOpGetDummyOpShape, NIL, NIL, TypeCheckStackPopOp, PrintStackOpDetails]];
StackOpKindDataBody: TYPE = RECORD[ordinaryWordType: WordType];
CopyStackBinOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF StackOpKindDataBody ← NARROW[op.data];
RETURN[CreateBinaryOp[inData.ordinaryWordType]];
END;
CopyPopOp: PROCEDURE[op: OpDescriptor] RETURNS[OpDescriptor] =
BEGIN
inData: REF StackOpKindDataBody ← NARROW[op.data];
RETURN[CreatePopOp[inData.ordinaryWordType]];
END;
CreateBinaryOp: PUBLIC PROCEDURE[ordinaryWordType: WordType] RETURNS[OpDescriptor] =
BEGIN
kind: OpKind ← binOpKind;
data: REF StackOpKindDataBody ← NEW[StackOpKindDataBody ← [ordinaryWordType]];
RETURN[NEW[OpDescriptorBody ← [kind, data]]];
END;
CreatePopOp: PUBLIC PROCEDURE[ordinaryWordType: WordType] RETURNS[OpDescriptor] =
BEGIN
kind: OpKind ← popOpKind;
data: REF StackOpKindDataBody ← NEW[StackOpKindDataBody ← [ordinaryWordType]];
RETURN[NEW[OpDescriptorBody ← [kind, data]]];
END;
TypeCheckStackBinOp: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF StackOpKindDataBody ← NARROW[op.data];
BasicNodeTypeCheck[node, 2, 1];
ArgPairTypeCheck[node.stackState, opData.ordinaryWordType, opData.ordinaryWordType];
ResultWordTypeCheck[opData.ordinaryWordType, node.arcs[first].stackState];
END;
TypeCheckStackPopOp: PROCEDURE[op: OpDescriptor, node: PGNode] =
BEGIN
opData: REF StackOpKindDataBody ← NARROW[op.data];
BasicNodeTypeCheck[node, 1, 0];
END;
PrintStackOpDetails: PROCEDURE[op: OpDescriptor, node: PGNode, on: IO.STREAM, nested: CARDINAL] =
{NULL};
-- module main procedures
END.
MODULE HISTORY
Initial by: Sturgis, March 17, 1984 2:58:45 pm PST
Remark: March 19, 1984 5:18:16 pm PST: did the trivial type check on a single arc.
Remark: March 20, 1984 2:18:43 pm PST: successfully split an arc using SplitADummyArc. BeginTypeCheck succeeded.
Remark: March 21, 1984 7:24:20 pm PST: successfully split an arc adding a loop.
Remark: March 21, 1984 7:31:10 pm PST: successfully split an arc adding a branch.
Remark: April 18, 1984 9:32:35 am PST: have added the basic print code, including a print sort procedure.
Remark: April 26, 1984 1:07:16 pm PST: basic program graph stuff works, including building a table of dummy arcs. Still have to get specific about actual dragon op codes, and still have to build the type tables to allow finding fields of appropriate type.
Chang;