Pass4L.Mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Satterthwaite, June 18, 1986 12:25:02 pm PDT
Paul Rovner, September 7, 1983 4:54 pm
Russ Atkinson (RRA) March 6, 1985 10:52:03 pm PST
DIRECTORY
Alloc: TYPE USING [Notifier],
BcdDefs: TYPE USING [Link, EPLimit, IRLinkLimit],
ComData: TYPE USING [idANY, importCtx, interface, linkCount, nBodies, nSigCodes, switches, textIndex],
CompilerUtil: TYPE USING [AppendBCDWord, AppendBCDWords],
Log: TYPE USING [Error, ErrorN, ErrorSei, WarningSei],
P4: TYPE USING [],
PrincOps: TYPE USING [
ControlLink, EPRange, globalbase, localbase, MaxFrameSize, MaxNGfi, Port, PsbIndex],
SourceMap: TYPE USING [Loc],
Symbols: TYPE USING [Base, BitAddress, BitCount, Type, UNSPEC, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, BTIndex, CBTIndex, nullName, ISENull, RecordSENull, CTXNull, BTNull, lL, RootBti, bodyType, ctxType, seType],
SymbolOps: TYPE USING [ArgCtx, ArgRecord, BitsForRange, Cardinality, DecodeBitAddr, DecodeCard, DecodeTreeIndex, DecodeType, EncodeBitAddr, EncodeCard, FirstCtxSe, LinkMode, MakeCtxSe, NextSe, PackedSize, TypeForm, UnderType, XferMode],
Target: TYPE MachineParms USING [PackedBitCount, bitsPerLongWord, bitsPerWord],
Tree: TYPE USING [Base, Index, Link, Scan, nullIndex, treeType],
TreeOps: TYPE USING [GetSe, ScanList, ToLoc];
Pass4L: PROGRAM
IMPORTS CompilerUtil, Log, SymbolOps, TreeOps, dataPtr: ComData
EXPORTS P4 = {
OPEN SymbolOps, Symbols;
tb: Tree.Base; -- tree base (local copy)
seb: Symbols.Base; -- se table base (local copy)
ctxb: Symbols.Base; -- context table base (local copy)
bb: Symbols.Base; -- body table base (local copy)
LayoutNotify: PUBLIC Alloc.Notifier = {
called by allocator whenever table area is repacked
tb ← base[Tree.treeType];
seb ← base[seType]; ctxb ← base[ctxType];
bb ← base[bodyType]};
address assignment (machine sensitive and subject to change)
wordLength: CARDINAL = Target.bitsPerWord;
longWordLength: CARDINAL = Target.bitsPerLongWord;
wordFill: CARDINAL = wordLength-1;
localOrigin: CARDINAL = PrincOps.localbase*wordLength;
localSlots: CARDINAL = 8;
globalOrigin: CARDINAL = PrincOps.globalbase*wordLength;
frameLimit: CARD = PrincOps.MaxFrameSize.LONG*wordLength;
entryLimit: CARDINAL = MIN[BcdDefs.EPLimit, PrincOps.MaxNGfi*PrincOps.EPRange];
BitsForType: PUBLIC PROC[type: Type] RETURNS[nBits: BitCount] = {
assumes (an attempt at) prior processing by P4.DeclItem
sei: CSEIndex = UnderType[type];
WITH seb[sei] SELECT FROM
basic => nBits ← length;
enumerated => nBits ← BitsForRange[Cardinality[sei]-1];
ref => nBits ← wordLength;
transfer => nBits ← wordLength * (SELECT mode FROM
proc => PrincOps.ControlLink.SIZE,
port => PrincOps.Port.SIZE,
signal, error => PrincOps.ControlLink.SIZE,
process => PrincOps.PsbIndex.SIZE,
program => PrincOps.ControlLink.SIZE,
ENDCASE => ERROR);
arraydesc => nBits ← 2*wordLength;
relative => nBits ← BitsForType[offsetType];
zone => nBits ← (IF mds THEN 1 ELSE 2)*wordLength;
long =>
nBits ← ((BitsForType[rangeType] + wordFill + (longWordLength-wordLength))/wordLength)*wordLength;
real => nBits ← longWordLength;
ENDCASE => { -- processing of se entry must be complete
IF ~mark4 THEN { -- P4declitem has not been able to complete
Log.ErrorSei[typeLength,
IF seb[type].seTag = id THEN LOOPHOLE[type, ISEIndex] ELSE ISENull];
RETURN[0]};
WITH seb[sei] SELECT FROM
record => nBits ← length;
array => {
n: CARD = Cardinality[indexType];
b: BitCount ← BitsForType[componentType];
IF packed AND (b#0 AND b<=Target.PackedBitCount.LAST) THEN { -- b IN PackedBitCount
itemsPerWord: CARDINAL = wordLength/PackedSize[b];
nBits ← IF n <= itemsPerWord
THEN n*PackedSize[b]
ELSE ((n+(itemsPerWord-1))/itemsPerWord)*wordLength}
ELSE {
b ← ((b + wordFill)/wordLength)*wordLength;
IF n > CARDINAL.LAST/b THEN Log.Error[arraySize];
nBits ← n*b}};
opaque => nBits ← length;
subrange => nBits ← IF empty THEN 0 ELSE BitsForRange[Cardinality[sei]-1];
ENDCASE => nBits ← 0};
RETURN};
profile utilities
VarLink: TYPE = RECORD [
SELECT kind: * FROM
symbol => [index: ISEIndex],
body => [index: CBTIndex],
empty => [],
ENDCASE];
VarInfo: TYPE = RECORD[link: VarLink, key: CARD];
VarInfoList: TYPE = RECORD[SEQUENCE length: NAT OF VarInfo];
Profile: TYPE = REF VarInfoList;
AllocateProfile: PROC[n: CARDINAL] RETURNS[profile: Profile] = {
profile ← NEW[VarInfoList[n]];
FOR k: CARDINAL IN [0 .. n) DO profile[k].link ← [empty[]] ENDLOOP;
RETURN};
SortProfile: PROC[v: Profile] = { -- Shell sort --
i, j: INTEGER;
k: CARDINAL;
t: VarInfo;
h: NAT ← v.length;
DO
h ← h/2;
FOR j IN [h .. v.length) DO
i ← j-h; k ← v[j].key; t ← v[j];
WHILE k > v[i].key DO
v[i+h] ← v[i];
IF (i ← i-h) < 0 THEN EXIT;
ENDLOOP;
v[i+h] ← t;
ENDLOOP;
IF h <= 1 THEN EXIT;
ENDLOOP};
MergeProfiles: PROC[profile1, profile2: Profile] RETURNS[profile: Profile] = {
i, i1, i2: CARDINAL ← 0;
profile ← NEW[VarInfoList[profile1.length+profile2.length]];
WHILE i1 < profile1.length AND i2 < profile2.length DO
IF profile1[i1].key > profile2[i2].key THEN {profile[i] ← profile1[i1]; i1 ← i1+1}
ELSE {profile[i] ← profile2[i2]; i2 ← i2+1};
i ← i + 1
ENDLOOP;
WHILE i1 < profile1.length DO
profile[i] ← profile1[i1]; i1 ← i1+1; i ← i + 1
ENDLOOP;
WHILE i2 < profile2.length DO
profile[i] ← profile2[i2]; i2 ← i2+1; i ← i + 1
ENDLOOP;
};
entry point assignment
GenBodies: PROC[root: BTIndex, proc: PROC[CBTIndex]] = {
bti, next: BTIndex;
FOR bti ← root, next UNTIL bti = BTNull DO
WITH bb[bti] SELECT FROM
Callable => proc[LOOPHOLE[bti]];
ENDCASE => NULL;
IF bb[bti].firstSon # BTNull THEN next ← bb[bti].firstSon
ELSE
DO
next ← bb[bti].link.index;
IF next = BTNull OR bb[bti].link.which # parent THEN EXIT;
bti ← next;
ENDLOOP;
ENDLOOP};
BodyRefs: PROC[bti: CBTIndex] RETURNS[count: CARDINAL𡤀] = {
sei: ISEIndex = bb[bti].id;
CountRefs: Tree.Scan = {
count ← count + DecodeCard[seb[TreeOps.GetSe[t]].idInfo]};
IF sei # ISENull THEN {
node: Tree.Index = DecodeTreeIndex[seb[sei].idValue];
TreeOps.ScanList[tb[node].son[1], CountRefs]};
RETURN};
AssignEntries: PUBLIC PROC[rootBti: BTIndex] = {
i, k: INTEGER;
profile: Profile;
bti: CBTIndex;
AssignSlot: PROC[bti: CBTIndex] = {
IF ~bb[bti].inline AND bb[bti].info.mark = Internal THEN {
n: CARDINAL = BodyRefs[bti];
profile[k].link ← [body[index: bti]];
WITH body: bb[bti] SELECT FROM
Inner => {body.frameOffset ← n; profile[k].key ← 0};
ENDCASE => profile[k].key ← n;
k ← k+1}};
nEntries: CARDINAL = MAX[dataPtr.nBodies, dataPtr.nSigCodes];
IF nEntries > entryLimit THEN Log.ErrorN[bodyEntries, nEntries-entryLimit];
profile ← AllocateProfile[dataPtr.nBodies];
k ← 0; GenBodies[rootBti, AssignSlot];
IF dataPtr.switches['s] THEN SortProfile[profile];
i ← 1;
FOR j: INTEGER IN [0..profile.length) DO
bti ← NARROW[profile[j].link, VarLink.body].index;
IF bti = RootBti THEN bb[bti].entryIndex ← 0
ELSE {bb[bti].entryIndex ← i; i ← i+1};
ENDLOOP;
profile ← NIL};
frame layout
FieldWordCount: TYPE = CARDINAL; -- [0..FieldBitCount.LAST/wordLength];
WordsForField: PROC[sei: ISEIndex] RETURNS[nW: FieldWordCount] = {
nBits: BitCount = BitsForType[seb[sei].idType] + wordFill;
IF nBits > BitCount.LAST THEN {
Log.ErrorSei[addressOverflow, sei]; nW ← FieldWordCount.LAST}
ELSE nW ← nBits/wordLength;
RETURN};
VarScan: TYPE = PROC[sei: ISEIndex, output: BOOL];
GenCtxVars: PROC[ctx: CTXIndex, p: VarScan, output: BOOL] = {
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO
IF ~seb[sei].constant THEN p[sei, output] ENDLOOP};
GenBodyVars: PROC[bti: CBTIndex, p: VarScan] = {
type: Type = bb[bti].ioType;
WITH se: seb[type] SELECT FROM
cons =>
WITH t: se SELECT FROM
transfer => {
GenCtxVars[ArgCtx[t.typeIn], p, FALSE];
GenCtxVars[ArgCtx[t.typeOut], p, TRUE]};
ENDCASE;
ENDCASE;
GenCtxVars[bb[bti].localCtx, p, FALSE]};
GenBodyProcs: PROC[bti: BTIndex, proc: PROC[CBTIndex]] = {
sonBti: BTIndex;
IF (sonBti ← bb[bti].firstSon) # BTNull THEN
DO
WITH body: bb[sonBti] SELECT FROM
Callable => IF ~body.inline THEN proc[LOOPHOLE[sonBti]];
ENDCASE => NULL;
IF bb[sonBti].link.which = parent THEN EXIT;
sonBti ← bb[sonBti].link.index;
ENDLOOP};
GenImportedVars: PROC[p: VarScan] = {
ctx: CTXIndex = dataPtr.importCtx;
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO
IF ~seb[sei].constant THEN p[sei, FALSE]
ELSE {
type: CSEIndex = UnderType[seb[sei].idType];
WITH seb[type] SELECT FROM definition => GenCtxVars[defCtx, p, FALSE] ENDCASE};
ENDLOOP};
MarkArg: VarScan = {seb[sei].mark4 ← TRUE};
MarkArgs: PROC[sei: Type] = {
type: CSEIndex = UnderType[sei];
rSei: RecordSEIndex;
WITH t: seb[type] SELECT FROM
transfer => {
IF (rSei ← ArgRecord[t.typeIn]) # RecordSENull THEN {
GenCtxVars[seb[rSei].fieldCtx, MarkArg, FALSE];
seb[rSei].length ← LayoutArgs[rSei, 0, TRUE]*wordLength;
seb[rSei].mark4 ← TRUE};
IF (rSei ← ArgRecord[t.typeOut]) # RecordSENull THEN {
GenCtxVars[seb[rSei].fieldCtx, MarkArg, TRUE];
seb[rSei].length ← LayoutArgs[rSei, 0, TRUE]*wordLength;
seb[rSei].mark4 ← TRUE};
t.mark4 ← TRUE};
ENDCASE};
EncodeBitAddress: PROC[wd, bd: CARDINAL] RETURNS[Symbols.UNSPEC] = INLINE {
RETURN[EncodeBitAddr[[bd: wd*wordLength + bd]]]};
LayoutLocals: PUBLIC PROC[bti: CBTIndex] RETURNS[length: CARDINAL] = {
vProfile: Profile;
vI: CARDINAL;
CountVar: VarScan = {
IF seb[sei].hash # nullName OR seb[sei].extended OR ~output THEN vI ← vI + 1};
CountProc: PROC[bti: CBTIndex] = {
IF bb[bti].info.mark = Internal THEN vI ← vI + 1};
InsertVar: VarScan = {
saveIndex: SourceMap.Loc = dataPtr.textIndex;
node: Tree.Index = DecodeTreeIndex[seb[sei].idValue];
nRefs: CARD = DecodeCard[seb[sei].idInfo];
IF node # Tree.nullIndex THEN dataPtr.textIndex ← TreeOps.ToLoc[tb[node].info];
IF seb[sei].hash # nullName OR seb[sei].extended OR ~output THEN {
vProfile[vI] ← [link: [symbol[sei]], key: nRefs]; vI ← vI+1};
IF nRefs = 0 AND seb[sei].hash # nullName
AND ~output -- suppress message for return record
AND node # Tree.nullIndex THEN Log.WarningSei[unusedId, sei];
seb[sei].idInfo ← EncodeCard[WordsForField[sei]*wordLength];
seb[sei].idValue ← EncodeCard[0];
dataPtr.textIndex ← saveIndex};
InsertProc: PROC[bti: CBTIndex] = {
IF bb[bti].info.mark = Internal THEN {
vProfile[vI] ← VarInfo[
link: [body[bti]],
key: WITH bb[bti] SELECT FROM Inner=>frameOffset, ENDCASE=>0];
vI ← vI+1}};
bodyType: Type = bb[bti].ioType;
origin: CARDINALIF bb[bti].level = lL THEN localOrigin ELSE localOrigin+wordLength;
IF ~seb[bodyType].mark4 THEN MarkArgs[bodyType];
vI ← 0; GenBodyVars[bti, CountVar]; GenBodyProcs[bti, CountProc];
vProfile ← AllocateProfile[vI];
vI ← 0; GenBodyVars[bti, InsertVar]; GenBodyProcs[bti, InsertProc];
SortProfile[vProfile];
origin ← AssignVars[vProfile, origin, localOrigin + localSlots*wordLength];
length ← AssignVars[vProfile, origin, frameLimit];
CheckFrameOverflow[vProfile]; vProfile ← NIL;
RETURN};
LayoutGlobals: PUBLIC PROC[bti: CBTIndex, stopping, fragments: BOOL]
RETURNS[length: CARDINAL] = {
vProfile, pProfile, xProfile: Profile;
vI, pI, xI: CARDINAL;
CountVar: VarScan = {
ctx: CTXIndex = seb[sei].idCtx;
IF ctxb[ctx].ctxType = imported OR ctx = dataPtr.importCtx THEN xI ← xI + 1
ELSE IF seb[sei].hash # nullName OR seb[sei].extended OR ~output THEN {
IF seb[sei].public THEN pI ← pI + 1 ELSE vI ← vI + 1};
};
InsertVar: VarScan = {
ctx: CTXIndex = seb[sei].idCtx;
nRefs: CARD = DecodeCard[seb[sei].idInfo];
IF ctxb[ctx].ctxType = imported OR ctx = dataPtr.importCtx THEN {
xProfile[xI] ← [link: [symbol[sei]], key: nRefs];
xI ← xI+1;
IF nRefs = 0 AND ~seb[sei].public THEN Log.WarningSei[unusedId, sei];
seb[sei].idInfo ← EncodeCard[WordsForField[sei]*wordLength]}
ELSE {
saveIndex: SourceMap.Loc = dataPtr.textIndex;
node: Tree.Index = DecodeTreeIndex[seb[sei].idValue];
IF node # Tree.nullIndex THEN dataPtr.textIndex ← TreeOps.ToLoc[tb[node].info];
IF seb[sei].hash # nullName OR seb[sei].extended OR ~output THEN {
IF seb[sei].public THEN {pProfile[pI] ← [link: [symbol[sei]], key: nRefs]; pI ← pI + 1}
ELSE {vProfile[vI] ← [link: [symbol[sei]], key: nRefs]; vI ← vI + 1}};
IF nRefs = 0 AND ~dataPtr.interface
AND ~seb[sei].public AND seb[sei].hash # nullName
AND node # Tree.nullIndex THEN Log.WarningSei[unusedId, sei];
seb[sei].idInfo ← EncodeCard[WordsForField[sei]*wordLength];
seb[sei].idValue ← EncodeCard[0];
dataPtr.textIndex ← saveIndex}};
origin: CARDINAL ← globalOrigin;
IF ~seb[bb[bti].ioType].mark4 THEN ERROR;
vI ← pI ← xI ← 0; GenBodyVars[bti, CountVar]; GenImportedVars[CountVar];
vProfile ← AllocateProfile[vI];
pProfile ← AllocateProfile[pI];
xProfile ← AllocateProfile[xI];
vI ← pI ← xI ← 0; GenBodyVars[bti, InsertVar]; GenImportedVars[InsertVar];
IF dataPtr.switches['s] THEN {
SortProfile[vProfile]; SortProfile[pProfile]; SortProfile[xProfile]};
AssignImports[xProfile, 0, 256*PrincOps.ControlLink.SIZE*wordLength];
SELECT TRUE FROM-- adjust for system uses of global 0
stopping => origin ← origin + wordLength;
fragments OR pProfile.length # 0 =>
avoid overlay of global 0 (used for start traps).
note that fragment length >= 2*wordLength
origin ← MAX[
AssignVars[vProfile, origin, globalOrigin+wordLength],
globalOrigin+wordLength];
ENDCASE;
IF pProfile.length # 0 THEN {
vProfile ← MergeProfiles[vProfile, pProfile]; pProfile ← NIL};
origin ← AssignVars[vProfile, origin, frameLimit];
length ← MAX[origin, globalOrigin+wordLength];
CheckFrameOverflow[vProfile]; vProfile ← NIL;
CheckFrameOverflow[xProfile]; xProfile ← NIL;
RETURN};
CheckBlock: PUBLIC PROC[bti: BTIndex] = {
CheckVar: VarScan = {
saveIndex: SourceMap.Loc = dataPtr.textIndex;
node: Tree.Index = DecodeTreeIndex[seb[sei].idValue];
IF node # Tree.nullIndex THEN {
dataPtr.textIndex ← TreeOps.ToLoc[tb[node].info];
IF DecodeCard[seb[sei].idInfo] = 0 THEN Log.WarningSei[unusedId, sei]};
dataPtr.textIndex ← saveIndex};
GenCtxVars[bb[bti].localCtx, CheckVar, FALSE]};
LayoutBlock: PUBLIC PROC[bti: BTIndex, origin: CARDINAL] RETURNS[length: CARDINAL] = {
vProfile: Profile;
vI: CARDINAL;
CountVar: VarScan = {vI ← vI + 1};
CountProc: PROC[bti: CBTIndex] = {
IF bb[bti].info.mark = Internal THEN vI ← vI + 1};
InsertVar: VarScan = {
vProfile[vI] ← [link: [symbol[sei]], key: DecodeCard[seb[sei].idInfo]]; vI ← vI+1;
seb[sei].idInfo ← EncodeCard[WordsForField[sei]*wordLength];
seb[sei].idValue ← EncodeCard[0]};
InsertProc: PROC[bti: CBTIndex] = {
IF bb[bti].info.mark = Internal THEN {
vProfile[vI] ← VarInfo[
link: [body[bti]],
key: WITH bb[bti] SELECT FROM Inner=>frameOffset, ENDCASE=>0];
vI ← vI+1}};
vI ← 0; GenCtxVars[bb[bti].localCtx, CountVar, FALSE]; GenBodyProcs[bti, CountProc];
vProfile ← AllocateProfile[vI];
vI ← 0; GenCtxVars[bb[bti].localCtx, InsertVar, FALSE]; GenBodyProcs[bti, InsertProc];
SortProfile[vProfile];
length ← AssignVars[vProfile, origin, frameLimit];
CheckFrameOverflow[vProfile]; vProfile ← NIL;
RETURN};
LayoutInterface: PUBLIC PROC[bti: CBTIndex] RETURNS[nEntries: CARDINAL] = {
epN: CARDINAL ← 0;
FOR sei: ISEIndex ← FirstCtxSe[bb[bti].localCtx], NextSe[sei] UNTIL sei = ISENull DO
SELECT LinkMode[sei] FROM
val, ref => {
seb[sei].linkSpace ← TRUE; seb[sei].idValue ← EncodeCard[epN]; epN ← epN + 1};
type => {seb[sei].idValue ← EncodeCard[epN]; epN ← epN + 1};
ENDCASE;
ENDLOOP;
IF (nEntries𡤎pN) > BcdDefs.IRLinkLimit THEN
Log.ErrorN[interfaceEntries, nEntries-BcdDefs.IRLinkLimit];
RETURN};
CheckFrameOverflow: PROC[profile: Profile] = {
FOR i: INTEGER IN [0 .. profile.length) DO
WITH profile[i].link SELECT FROM
symbol => Log.ErrorSei[addressOverflow, index];
body => Log.ErrorSei[addressOverflow, bb[index].id];
ENDCASE;
ENDLOOP};
Align: PROC[offset: CARDINAL, item: VarLink] RETURNS[CARDINAL] = {
RETURN[WITH item SELECT FROM
body => (offset+wordLength)/(4*wordLength)*(4*wordLength) + (2*wordLength),
symbol =>
SELECT XferMode[seb[index].idType] FROM
port => (offset+wordLength)/(4*wordLength)*(4*wordLength) + (2*wordLength),
ENDCASE => offset,
ENDCASE => offset]};
BitWidth: PROC[item: VarLink] RETURNS[CARDINAL] = {
RETURN[WITH item SELECT FROM
symbol => DecodeCard[seb[index].idInfo],
body => PrincOps.ControlLink.SIZE*wordLength.LONG,
ENDCASE => (0).LONG]
};
AssignBase: PROC[item: VarLink, base: CARDINAL] = {
WITH item SELECT FROM
symbol => {
sei: ISEIndex = index;
seb[sei].idValue ← EncodeBitAddress[wd:base/wordLength, bd:0];
seb[sei].mark4 ← TRUE};
body => {
bti: CBTIndex = index;
WITH bb[bti] SELECT FROM
Inner => frameOffset ← base/wordLength;
ENDCASE => ERROR};
ENDCASE
};
AssignVars: PROC[profile: Profile, origin, limit: CARD] RETURNS[CARDINAL] = {
start, base, length, remainder, delta: CARDINAL;
i, j, next: INTEGER;
t: VarLink;
found, skips: BOOL;
next ← 0; start ← origin;
remainder ← IF origin < limit THEN limit - origin ELSE 0;
WHILE next < profile.length DO
i ← next; found ← skips ← FALSE;
WHILE ~found AND i < profile.length DO
IF (t ← profile[i].link) # [empty[]] THEN {
base ← Align[start, t]; length ← BitWidth[t];
delta ← base - start;
IF length + delta <= remainder THEN {
limit: CARDINAL = base + length;
subBase: CARDINAL ← start;
nRefs: CARDINAL ← 0;
FOR j ← i+1, j+1 WHILE j < profile.length AND subBase < limit DO
IF profile[j].link # [empty[]] THEN {
subLength: CARDINAL = BitWidth[profile[j].link];
subDelta: CARDINAL = Align[subBase, profile[j].link] - subBase;
IF (subDelta + subLength) > (limit - subBase) THEN EXIT;
subBase ← subBase + (subDelta + subLength);
nRefs ← nRefs + profile[j].key};
ENDLOOP;
IF nRefs <= profile[i].key OR ~dataPtr.switches['s] THEN {
found ← TRUE;
AssignBase[t, base]; profile[i].link ← [empty[]];
IF base # start AND dataPtr.switches['s] THEN
[] ← AssignVars[profile, start, base];
start ← limit;
remainder ← remainder - (length+delta)}
ELSE IF ~skips THEN {skips ← TRUE; next ← i}}};
i ← i+1;
IF ~skips THEN next ← i;
ENDLOOP;
ENDLOOP;
RETURN[start]};
AssignImports: PROC[profile: Profile, origin, limit: CARDINAL] = {
i, nProcs: CARDINAL ← profile.length;
next: CARDINAL;
t: VarLink;
v: VarInfo;
UNTIL i = 0 DO
i ← i-1; t ← profile[i].link;
WITH t SELECT FROM
symbol =>
IF XferMode[seb[index].idType] # proc THEN {
nProcs ← nProcs-1; v ← profile[i];
FOR j: CARDINAL IN [i..nProcs) DO profile[j] ← profile[j+1] ENDLOOP;
profile[nProcs] ← v};
ENDCASE;
ENDLOOP;
the frame link fragment begins at origin
dataPtr.linkCount ← profile.length;
IF ~dataPtr.interface THEN CompilerUtil.AppendBCDWord[profile.length];
i ← profile.length;
next ← MIN[origin + profile.length*BcdDefs.Link.SIZE*wordLength, limit];
UNTIL i = 0 OR next = origin DO
i ← i-1; t ← profile[i].link; profile[i].link ← [empty[]];
IF ~dataPtr.interface THEN
WITH t SELECT FROM
symbol => {
sei: ISEIndex = index;
next ← next - DecodeCard[seb[sei].idInfo];
CompilerUtil.AppendBCDWords[@seb[sei].idValue, BcdDefs.Link.SIZE];
seb[sei].idValue ← EncodeBitAddress[wd: next/wordLength, bd: 0];
seb[sei].linkSpace ← TRUE};
ENDCASE;
ENDLOOP};
parameter record layout
LayoutArgs: PUBLIC PROC[argRecord: RecordSEIndex, origin: CARDINAL, body: BOOL]
RETURNS[CARDINAL] = {
w: CARDINAL ← origin;
IF argRecord # RecordSENull THEN {
ctx: CTXIndex = seb[argRecord].fieldCtx;
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO
nW: FieldWordCount = WordsForField[sei];
IF nW = 0 THEN Log.ErrorSei[sizeClash, sei];
IF ~body THEN {
seb[sei].idInfo ← EncodeCard[nW*wordLength];
seb[sei].idValue ← EncodeBitAddress[wd:w, bd:0]};
w ← w + nW;
ENDLOOP};
RETURN[w]};
record layout
BitOffset: PROC[sei: ISEIndex] RETURNS[CARDINAL] = {
t: BitAddress = DecodeBitAddr[seb[sei].idValue];
RETURN[t.bd]};
BitsForField: PROC[sei: ISEIndex] RETURNS[nB: BitCount] = {
nBits: BitCount = BitsForType[seb[sei].idType];
IF nBits > BitCount.LAST THEN {
Log.ErrorSei[addressOverflow, sei]; nB ← 0}
ELSE nB ← nBits;
RETURN};
ScanVariants: PROC[caseCtx: CTXIndex, proc: PROC[RecordSEIndex] RETURNS[BOOL]]
RETURNS[BOOL] = {
FOR sei: ISEIndex ← FirstCtxSe[caseCtx], NextSe[sei] UNTIL sei = ISENull DO
rSei: Type = DecodeType[seb[sei].idInfo];
WITH variant: seb[rSei] SELECT FROM
cons =>
WITH variant SELECT FROM
record => IF proc[LOOPHOLE[rSei]] THEN RETURN[TRUE];
ENDCASE => ERROR;
ENDCASE => NULL; -- skip multiple identifiers
ENDLOOP;
RETURN[FALSE]};
LayoutFields: PUBLIC PROC[rSei: RecordSEIndex, offset: CARDINAL] = {
maxRecordSize: CARDINAL = CARDINAL.LAST/wordLength + 1;
w: CARD;
b: CARDINAL;
lastFillable: BOOL;
lastSei: ISEIndex;
AssignField: PROC[sei: ISEIndex] = {
OPEN id: seb[sei];
n: BitCount;
nW, nB: CARDINAL;
saveIndex: SourceMap.Loc = dataPtr.textIndex;
dataPtr.textIndex ← TreeOps.ToLoc[tb[DecodeTreeIndex[id.idValue]].info];
n ← BitsForField[sei];
nW ← n/wordLength; nB ← n MOD wordLength;
IF nW > 0 AND nB # 0 THEN {nW ← nW+1; nB ← 0};
IF (nW > 0 OR b+nB > wordLength OR n = 0) AND b # 0 THEN {w ← w+1; b ← 0};
dataPtr.textIndex ← saveIndex;
IF b = 0 AND lastFillable THEN FillWord[lastSei];
IF w >= maxRecordSize THEN Log.ErrorSei[addressOverflow, sei];
id.idInfo ← EncodeCard[nW*wordLength + nB];
id.idValue ← EncodeBitAddress[wd:w, bd:b];
lastSei ← sei; lastFillable ← (nW = 0 AND n # 0);
w ← w + nW; b ← b + nB;
IF b >= wordLength THEN {w ← w+1; b ← b - wordLength};
IF (IF b=0 THEN w ELSE w+1) >= maxRecordSize THEN
Log.ErrorSei[addressOverflow, sei]};
FillWord: PROC[sei: ISEIndex] = {
t: BitAddress = DecodeBitAddr[seb[sei].idValue];
width: CARDINAL = wordLength - t.bd;
IF seb[rSei].machineDep AND width # DecodeCard[seb[sei].idInfo] THEN
Log.WarningSei[paddedField, sei];
seb[sei].idInfo ← EncodeCard[width]};
FindFit: PROC[vSei: RecordSEIndex] RETURNS[BOOL] = {
sei: ISEIndex ← FirstCtxSe[seb[vSei].fieldCtx];
type: CSEIndex;
IF sei = ISENull THEN RETURN[FALSE];
type ← UnderType[seb[sei].idType];
WITH seb[type] SELECT FROM
union =>
IF controlled THEN sei ← tagSei
ELSE RETURN[ScanVariants[caseCtx, FindFit]];
sequence => IF controlled THEN sei ← tagSei ELSE RETURN[FALSE];
ENDCASE => NULL;
RETURN[BitsForType[seb[sei].idType] + b <= wordLength]};
vOrigin: CARDINAL;
maxLength: CARDINAL;
AssignVariant: PROC[vSei: RecordSEIndex] RETURNS[BOOL] = {
LayoutFields[vSei, vOrigin];
maxLength ← MAX[seb[vSei].length, maxLength];
RETURN[FALSE]};
eqLengths: BOOL;
padEnd: CARDINAL;
PadVariant: PROC[vSei: RecordSEIndex] RETURNS[BOOL] = {
fillSei: ISEIndex ← ISENull;
type: CSEIndex;
fillOrigin, currentEnd: CARDINAL;
ctx: CTXIndex = seb[vSei].fieldCtx;
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO
IF DecodeBitAddr[seb[sei].idValue].bd/wordLength # w THEN EXIT;
fillSei ← sei;
ENDLOOP;
IF fillSei # ISENull THEN {
fillOrigin ← BitOffset[fillSei];
currentEnd ← fillOrigin + DecodeCard[seb[fillSei].idInfo];
IF currentEnd < padEnd AND (currentEnd # 0 OR padEnd < wordLength) THEN {
type ← UnderType[seb[fillSei].idType];
WITH seb[type] SELECT FROM
union => {
saveLastSei: ISEIndex = lastSei;
IF controlled THEN lastSei ← tagSei; -- for messages only
[] ← ScanVariants[caseCtx, PadVariant];
lastSei ← saveLastSei};
ENDCASE => IF seb[rSei].machineDep THEN Log.WarningSei[paddedField, fillSei];
seb[fillSei].idInfo ← EncodeCard[padEnd - fillOrigin]}}
ELSE IF vOrigin < padEnd AND (vOrigin # 0 OR padEnd < wordLength) THEN {
IF seb[rSei].machineDep THEN Log.WarningSei[paddedField, lastSei];
fillSei ← MakeCtxSe[nullName, CTXNull];
seb[fillSei].public ← TRUE; seb[fillSei].extended ← FALSE;
seb[fillSei].constant ← seb[fillSei].immutable ← FALSE;
seb[fillSei].linkSpace ← FALSE;
seb[fillSei].idType ← dataPtr.idANY;
seb[fillSei].idValue ← EncodeBitAddress[wd:w, bd:b];
seb[fillSei].idInfo ← EncodeCard[padEnd - vOrigin];
seb[fillSei].mark3 ← seb[fillSei].mark4 ← TRUE;
WITH seb[fillSei] SELECT FROM linked => link ← ctxb[ctx].seList ENDCASE => ERROR;
ctxb[ctx].seList ← fillSei};
seb[vSei].length ← MIN[
maxLength,
(seb[vSei].length + wordFill)/wordLength * wordLength];
IF seb[vSei].length # maxLength THEN eqLengths ← FALSE;
RETURN[FALSE]};
type: CSEIndex;
ctx: CTXIndex = seb[rSei].fieldCtx;
w ← offset/wordLength; b ← offset MOD wordLength;
lastFillable ← FALSE; lastSei ← ISENull;
FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO
IF ~seb[sei].constant THEN {
type ← UnderType[seb[sei].idType];
WITH seb[type] SELECT FROM
union => {
IF ~controlled THEN seb[sei].idValue ← EncodeBitAddress[wd:w, bd:b]
ELSE {AssignField[tagSei]; seb[sei].idValue ← seb[tagSei].idValue};
IF lastFillable AND b # 0 AND ~ScanVariants[caseCtx, FindFit] THEN {
FillWord[lastSei]; w ← w+1; b ← 0};
maxLength ← vOrigin ← w*wordLength + b;
[] ← ScanVariants[caseCtx, AssignVariant];
padEnd ← IF maxLength < wordLength
THEN maxLength
ELSE MAX[(vOrigin + wordFill)/wordLength, 1]*wordLength;
eqLengths ← TRUE;
[] ← ScanVariants[caseCtx, PadVariant];
hints.equalLengths ← eqLengths;
seb[sei].idInfo ← EncodeCard[
(maxLength - vOrigin)
+
(IF controlled THEN DecodeCard[seb[tagSei].idInfo] ELSE (0).LONG)];
w ← maxLength/wordLength; b ← maxLength MOD wordLength;
lastFillable ← FALSE};
sequence => {
IF ~controlled THEN seb[sei].idValue ← EncodeBitAddress[wd:w, bd:b]
ELSE {AssignField[tagSei]; seb[sei].idValue ← seb[tagSei].idValue};
IF lastFillable AND b # 0 THEN {FillWord[lastSei]; w ← w+1; b ← 0};
seb[sei].idInfo ← EncodeCard[(CARDINAL[w]*wordLength+b) - BitOffset[sei]];
lastFillable ← FALSE};
ENDCASE => AssignField[sei]};
ENDLOOP;
IF lastFillable AND b # 0 AND w > 0 THEN {FillWord[lastSei]; b ← 0; w ← w+1};
seb[rSei].length ← w*wordLength + b};
CheckFields: PUBLIC PROC[rSei: RecordSEIndex, origin: CARDINAL] = {
vProfile: Profile;
vI: CARDINAL;
CountVar: VarScan = {vI ← vI + 1};
InsertVar: VarScan = {
vProfile[vI] ← [link:[symbol[sei]], key:BitOffset[sei]]; vI ← vI+1};
b, newB: CARDINAL;
sei, lastSei: ISEIndex;
vI ← 0; GenCtxVars[seb[rSei].fieldCtx, CountVar, FALSE];
vProfile ← AllocateProfile[vI];
vI ← 0; GenCtxVars[seb[rSei].fieldCtx, InsertVar, FALSE];
SortProfile[vProfile];
b ← origin; lastSei ← ISENull;
FOR vI DECREASING IN [0 .. vProfile.length) DO
sei ← NARROW[vProfile[vI].link, VarLink.symbol].index;
SELECT TypeForm[seb[sei].idType] FROM
union => CheckVariants[sei];
sequence => {
IF vI # 0 THEN Log.ErrorSei[recordOverlap, sei];
CheckSequence[sei]};
ENDCASE;
SELECT (newB ← vProfile[vI].key) FROM
> b => Log.ErrorSei[recordGap, lastSei];
< b => Log.ErrorSei[recordOverlap, sei];
ENDCASE;
b ← newB + DecodeCard[seb[sei].idInfo]; lastSei ← sei;
ENDLOOP;
vProfile ← NIL;
IF b > wordLength AND b MOD wordLength # 0
THEN {
Log.ErrorSei[recordGap, lastSei];
b ← ((b+wordFill)/wordLength) * wordLength};
seb[rSei].length ← b};
CheckVariants: PROC[sei: ISEIndex] = {
type: CSEIndex = UnderType[seb[sei].idType];
started: BOOLFALSE;
eqLengths: BOOLTRUE;
gaps: BOOLFALSE;
origin, maxLength, size: CARDINAL;
CheckVariant: PROC[rSei: RecordSEIndex] RETURNS[BOOL] = {
length: CARDINAL;
CheckFields[rSei, origin]; length ← seb[rSei].length;
IF ~started THEN {maxLength ← length; started ← TRUE}
ELSE {
IF length MOD wordLength # 0 OR maxLength MOD wordLength # 0 THEN gaps ← TRUE;
IF length # maxLength THEN {maxLength ← MAX[length, maxLength]; eqLengths ← FALSE}};
RETURN[FALSE]};
origin ← BitOffset[sei];
WITH union: seb[type] SELECT FROM
union => {
IF union.controlled THEN {
newOrigin: CARDINAL = BitOffset[union.tagSei];
IF origin # newOrigin THEN Log.ErrorSei[fieldPosition, union.tagSei];
origin ← newOrigin + DecodeCard[seb[union.tagSei].idInfo]};
[] ← ScanVariants[union.caseCtx, CheckVariant];
size ← maxLength - BitOffset[sei]; union.hints.equalLengths ← eqLengths;
IF gaps THEN Log.ErrorSei[recordGap, sei];
SELECT DecodeCard[seb[sei].idInfo] FROM
0 => seb[sei].idInfo ← EncodeCard[size];
size => NULL;
ENDCASE => Log.ErrorSei[fieldPosition, sei]};
ENDCASE => ERROR};
CheckSequence: PROC[sei: ISEIndex] = {
type: CSEIndex = UnderType[seb[sei].idType];
origin, length: CARDINAL;
origin ← BitOffset[sei];
WITH seq: seb[type] SELECT FROM
sequence => {
IF seq.controlled THEN {
newOrigin: CARDINAL = BitOffset[seq.tagSei];
IF origin # newOrigin THEN Log.ErrorSei[fieldPosition, seq.tagSei];
origin ← newOrigin + DecodeCard[seb[seq.tagSei].idInfo]};
IF origin MOD wordLength # 0 THEN Log.ErrorSei[fieldPosition, sei];
length ← origin - BitOffset[sei];
SELECT DecodeCard[seb[sei].idInfo] FROM
0 => seb[sei].idInfo ← EncodeCard[length];
length => NULL;
ENDCASE => Log.ErrorSei[fieldPosition, sei]};
ENDCASE => ERROR};
}.