C2CAddressingImpl.mesa
Copyright Ó 1987, 1988, 1990, 1991, 1993 by Xerox Corporation. All rights reserved.
Christian Jacobi, April 4, 1988 11:45:20 am PDT
Christian Jacobi, February 24, 1993 3:56 pm PST
DIRECTORY
C2CAddressing,
C2CBasics,
C2CDefs,
C2CEmit,
C2CMode,
C2CIntCodeUtils,
C2CTarget,
IntCodeDefs,
IntCodeUtils;
C2CAddressingImpl: CEDAR PROGRAM
IMPORTS C2CBasics, C2CEmit, C2CIntCodeUtils, C2CMode, C2CTarget
EXPORTS C2CAddressing =
BEGIN
OPEN IntCodeDefs, C2CAddressing, C2CDefs, C2CBasics, C2CMode;
AddressMode: TYPE = C2CAddressing.AddressMode;
bPW: INT = C2CTarget.bitsPerWord;
bPHW: INT = C2CTarget.bitsPerHalfWord;
SimpleForLHSMaskNShift: PROC [base: Node] RETURNS [BOOL] = {
IF base.bits>C2CTarget.maxBitsForSimpleStructs THEN RETURN [FALSE];
WITH base SELECT FROM
var: Var =>
WITH var.location SELECT FROM
local: LocalVarLocation => RETURN [TRUE];
global: GlobalVarLocation => RETURN [TRUE];
ENDCASE => RETURN [FALSE];
ENDCASE => RETURN [FALSE];
};
FalseLHS: PROC [lhs: BOOL] RETURNS [BOOL] = INLINE {
IF lhs THEN CantHappen;
RETURN [lhs]
};
GetCondAddrMode: PROC [cond: CondNode, lhs: BOOL, wrongSize: BOOL, usedSz: INT] RETURNS [mode: Mode] = {
CombineAModes: PROC [c, x: AddressMode] RETURNS [AddressMode¬bad] = {
IF c=skip OR x=skip THEN {IF c#x THEN CantHappen; RETURN [skip]};
IF c=plain THEN RETURN [x];
IF x=plain THEN RETURN [c];
IF c=value OR x=value THEN RETURN [value];
IF c=x THEN RETURN [c];
IF c=assBitAddr OR x=assBitAddr THEN RETURN [assBitAddr];
IF c=getBitAddr OR x=getBitAddr THEN RETURN [assBitAddr];
NotYetImpl;
};
isFirst: BOOL ¬ TRUE;
sz: INT ¬ cond.bits;
am: AddressMode ¬ bad;
IF lhs THEN CantHappen;
FOR case: CaseList ¬ cond.cases, case.rest WHILE case#NIL DO
m1: Mode ¬ ProposedMode[case.body, lhs, wrongSize, usedSz];
am1: AddressMode ¬ GetAMode[m1];
SELECT am1 FROM
maskNShift => am1 ¬ value;
lHSMaskNShift => am1 ¬ getBitAddr;
bad => CantHappen;
ENDCASE => {};
IF isFirst THEN {isFirst¬FALSE; am¬am1};
mode ¬ DSetAMode[mode, CombineAModes[am, am1]];
FreeMode[m1];
ENDLOOP;
IF isFirst THEN CantHappen;
SELECT GetAMode[mode] FROM
skip, assBitAddr, assAddr, assUnits, assBits => {};
plain => SELECT TRUE FROM
sz=0 => mode ¬ DSetAMode[mode, getAddr];
sz>C2CTarget.bitsPerWord =>
IF sz=C2CTarget.TemporaryBits[sz]
THEN mode ¬ DSetAMode[mode, getAddr]
ELSE mode ¬ DSetAMode[mode, assBitAddr];
ENDCASE => {};
value, maskNShift => {};
getAddr => {};
getBitAddr => mode ¬ DSetAMode[mode, assBitAddr];
ENDCASE => CaseMissing;
};
ProposedMode: PUBLIC PROC [node: Node, lhs: BOOL, wrongSize: BOOL, usedSz: INT] RETURNS [mode: Mode] = {
--gets "minimal" mode with which this node can be adressed
Make: PROC [am: AddressMode] RETURNS [m: Mode] = {
m ¬ SetAMode[NIL, am];
IF lhs THEN {
temp: Mode ¬ m;
m ¬ SetLHS[m, TRUE];
FreeMode[temp]
};
};
GetListAddrMode: PROC [nl: NodeList, lhs: BOOL, wrongSize: BOOL, usedSz: INT] RETURNS [mode: Mode] = {
last: Node ¬ C2CIntCodeUtils.LastNodeWithCode[nl];
IF last=NIL
THEN CantHappen
ELSE RETURN ProposedMode[last, lhs, wrongSize, usedSz];
};
WITH node SELECT FROM
var: Var => RETURN [ProposedModeForVar[var, lhs, wrongSize, usedSz]];
apply: ApplyNode => {--bits are defined even if wrongSize!
IF lhs THEN CantHappen;
IF apply.handler=NIL THEN {
WITH apply.proc SELECT FROM
op: OperNode => {
WITH op.oper SELECT FROM
arithOp: ArithOper => IF arithOp.class.precision=C2CTarget.bitsPerDoubleWord AND arithOp.class.kind=real THEN RETURN [Make[assUnits]];
ENDCASE => {}
};
ENDCASE => {}
};
IF node.bits>bPW THEN {
--Occurs with ALL constructor and double precision
IF (node.bits MOD bPW)=0
THEN RETURN [Make[plain]]
ELSE RETURN [Make[favoriteBitAMode]]
};
IF node.bits=0 THEN RETURN [Make[skip]];
RETURN [Make[value]];
};
const: ConstNode => {--bits are defined even if wrongSize!
IF lhs OR node.bits=0 THEN CantHappen;
IF node.bits>bPW OR const.kind=numLiteral
THEN RETURN [Make[plain]] --we will make a template
ELSE RETURN [Make[value]];
};
assign: AssignNode => {--bits are defined independent of wrongSize!
--too simple ??
m: Mode;
IF lhs THEN CantHappen;
IF assign.lhs.bits<=bPW THEN RETURN [Make[value]]; --too simple !!
mode ¬ ProposedModeForVar[assign.lhs, TRUE, FALSE, assign.lhs.bits];
SELECT GetAMode[mode] FROM
plain => {
m ¬ ProposedMode[assign.rhs, FALSE, FALSE, assign.rhs.bits];
SELECT GetAMode[m] FROM
plain => {FreeMode[m]; RETURN [Make[plain]]};
ENDCASE => NULL;
};
ENDCASE => NULL;
FreeMode[mode];
RETURN [Make[favoriteBitAMode]];
};
block: BlockNode => RETURN [GetListAddrMode[block.nodes, lhs, wrongSize, usedSz]];
source: SourceNode => RETURN [GetListAddrMode[source.nodes, lhs, wrongSize, usedSz]];
decl: DeclNode => RETURN [ProposedModeForVar[decl.var, FalseLHS[lhs], FALSE, usedSz]];
enable: EnableNode => RETURN [GetListAddrMode[enable.scope, FalseLHS[lhs], FALSE, usedSz]];
cond: CondNode => {
--eg: h ← IF x THEN 9 ELSE 11;
RETURN GetCondAddrMode[cond, FalseLHS[lhs], wrongSize, usedSz];
};
oper: OperNode => {
[] ¬ FalseLHS[lhs];
RETURN [Make[value]];
};
machineCode: MachineCodeNode => {
[] ¬ FalseLHS[lhs];
RETURN [Make[value]];
};
module: ModuleNode => CantHappen;
goto: GotoNode => CantHappen;
lab: LabelNode => RETURN [ProposedMode[lab.label.node, lhs, wrongSize, usedSz]];
lambda: LambdaNode => CantHappen;
return: ReturnNode => {
IF lhs THEN CantHappen;
RETURN [Make[value]];
};
comment: CommentNode => CantHappen;
ENDCASE => {
IF node#NIL THEN CaseMissing;
IF lhs OR usedSz>bPW OR wrongSize
THEN RETURN [Make[plain]]
ELSE RETURN [Make[value]]
};
CantHappen;
};
AlignGCD: PROC [preXsz, newXsz: INT] RETURNS [INT] = {
--given an array with element size idxs at an alignment al, returns alignment of fields
--idxs 0 means there is no array: noop
IF preXsz>0 AND newXsz>0 THEN {
r: INT ¬ preXsz MOD newXsz;
WHILE r>0 DO
preXsz ¬ newXsz; newXsz ¬ r; r ¬ preXsz MOD newXsz;
ENDLOOP;
};
RETURN [newXsz];
};
GoodCaseAM: PROC [am: AddressMode] RETURNS [AddressMode] = {
RETURN [am];
};
BadCaseAM: PROC [am: C2CAddressing.AddressMode] RETURNS [C2CAddressing.AddressMode] = {
SELECT am FROM
dummy, skip => CantHappen;
getAddr, plain, maskNShift => am ¬ getBitAddr;
assBitAddr, assAddr => am ¬ assBitAddr;
assUnits => am ¬ assBits;
ENDCASE => {NotYetImpl};
RETURN [am];
};
favoriteBitAMode: AddressMode ¬ getBitAddr;
MakeMaskNShift: PROC [lhs: BOOL, unitSize: INT] RETURNS [m: Mode] = {
IF lhs
THEN {
temp: Mode ¬ SetAMode[NIL, lHSMaskNShift];
m ¬ C2CMode.SetLHS[temp, TRUE];
FreeMode[temp];
}
ELSE {
m ¬ SetAMode[NIL, maskNShift];
};
m ¬ C2CMode.DSetUnitSize[m, unitSize];
};
ProposedModeForField: PROC [var: Var, lhs: BOOL, wrongSize: BOOL, usedSz: INT] RETURNS [Mode] = {
Make: PROC [am: AddressMode] RETURNS [m: Mode] = {
m ¬ SetAMode[NIL, am];
IF lhs THEN {
temp: Mode ¬ m;
m ¬ SetLHS[m, TRUE];
FreeMode[temp]
};
};
field: FieldLocation ~ NARROW[var.location];
baseMode: Mode ¬ NIL;
IF wrongSize
THEN {
SELECT TRUE FROM
usedSz=0 => {
IF field.start MOD C2CTarget.bitsPerAddressUnit # 0 THEN RETURN [Make[favoriteBitAMode]];
RETURN [Make[getAddr]];
};
usedSz=C2CTarget.bitsPerWord => {
IF field.start MOD C2CTarget.bitsPerWord # 0 THEN {
RETURN [Make[favoriteBitAMode]];
};
baseMode ¬ ProposedMode[field.base, lhs, TRUE, C2CTarget.bitsPerWord];
IF GetAMode[baseMode]=lHSMaskNShift THEN {
baseMode ¬ DSetAMode[baseMode, getBitAddr];
};
RETURN [baseMode];
};
usedSz>C2CTarget.bitsPerWord => {
IF usedSz MOD C2CTarget.bitsPerWord # 0 THEN RETURN [Make[favoriteBitAMode]];
IF usedSz MOD C2CTarget.bestAlignment # 0 THEN
RETURN [Make[favoriteBitAMode]];
IF field.start MOD C2CTarget.bitsPerWord # 0 THEN
RETURN [Make[favoriteBitAMode]];
IF field.start MOD C2CTarget.bestAlignment # 0 THEN
RETURN [Make[favoriteBitAMode]];
baseMode ¬ ProposedMode[field.base, lhs, TRUE, C2CTarget.bestAlignment];
IF GetAMode[baseMode]=lHSMaskNShift THEN
baseMode ¬ DSetAMode[baseMode, getBitAddr];
RETURN [baseMode];
};
usedSz<C2CTarget.bitsPerWord => {
unitSz: INT ¬ C2CTarget.PointeeBits[usedSz];
off: INT ¬ field.start MOD unitSz;
pseudoUnitSz: INT ¬ C2CTarget.PointeeBits[usedSz+off];
baseMode ¬ ProposedMode[field.base, lhs, TRUE, pseudoUnitSz];
SELECT GetAMode[baseMode] FROM
plain => {
IF off=0 AND unitSz=usedSz
THEN RETURN [baseMode]
ELSE {
FreeMode[baseMode];
RETURN [MakeMaskNShift[lhs, pseudoUnitSz]];
};
};
getAddr => {
IF off=0 AND unitSz=usedSz
THEN RETURN [baseMode]
ELSE {
FreeMode[baseMode];
RETURN [MakeMaskNShift[lhs, pseudoUnitSz]];
};
};
value, maskNShift => {
FreeMode[baseMode];
IF lhs
THEN RETURN [Make[favoriteBitAMode]]
ELSE RETURN [MakeMaskNShift[FALSE, pseudoUnitSz]];
};
ENDCASE => {
FreeMode[baseMode];
RETURN [Make[favoriteBitAMode]];
};
}
ENDCASE => CantHappen;
}
ELSE { --known size
SELECT TRUE FROM
var.bits=C2CTarget.bitsPerWord => {
IF usedSz<=0
THEN {
IF field.start MOD C2CTarget.bitsPerAddressUnit # 0 THEN RETURN [Make[favoriteBitAMode]];
}
ELSE {
IF field.start MOD C2CTarget.bitsPerWord # 0 THEN RETURN [Make[favoriteBitAMode]]
};
baseMode ¬ ProposedMode[field.base, lhs, TRUE, IF usedSz=0 THEN 0 ELSE var.bits];
RETURN [baseMode];
};
var.bits>C2CTarget.bitsPerWord => {
IF usedSz=0
THEN {
IF var.bits MOD C2CTarget.bitsPerAddressUnit # 0
THEN RETURN [Make[favoriteBitAMode]];
IF field.start MOD C2CTarget.bitsPerAddressUnit # 0
THEN RETURN [Make[favoriteBitAMode]];
}
ELSE {
IF var.bits MOD C2CTarget.bitsPerWord # 0
THEN RETURN [Make[favoriteBitAMode]];
IF var.bits MOD C2CTarget.bestAlignment # 0
THEN RETURN [Make[favoriteBitAMode]];
IF field.start MOD C2CTarget.bitsPerWord # 0
THEN RETURN [Make[favoriteBitAMode]];
IF field.start MOD C2CTarget.bestAlignment # 0
THEN RETURN [Make[favoriteBitAMode]];
};
baseMode ¬ ProposedMode[field.base, lhs, TRUE, IF usedSz=0 THEN 0 ELSE var.bits];
IF GetAMode[baseMode]=lHSMaskNShift THEN RETURN [Make[getBitAddr]];
IF var.bits MOD 8 # 0 THEN baseMode ¬ DSetAMode[baseMode, getBitAddr];
RETURN [baseMode];
};
var.bits<C2CTarget.bitsPerWord => {
unitSz: INT ¬ C2CTarget.PointeeBits[var.bits];
off: INT ¬ field.start MOD unitSz;
pseudoUnitSz: INT ¬ C2CTarget.PointeeBits[var.bits+off];
IF pseudoUnitSz>C2CTarget.bitsPerWord THEN RETURN [Make[favoriteBitAMode]];
baseMode ¬ ProposedMode[field.base, lhs, TRUE, IF usedSz=0 THEN 0 ELSE pseudoUnitSz];
SELECT GetAMode[baseMode] FROM
plain => {
IF off=0 AND unitSz=var.bits
THEN {
IF C2CTarget.takingAddressIsExpensive THEN BEGIN --special hack to prevent taking the address of a variable in case it could be put into a register
WITH field.base SELECT FROM
bvar: Var => WITH bvar.location SELECT FROM
bloc: LocalVarLocation => IF bvar.bits<=bPW AND ~bvar.flags[addressed] AND ~bvar.flags[upLevel] THEN {
FreeMode[baseMode];
RETURN [MakeMaskNShift[lhs, pseudoUnitSz]];
};
ENDCASE => {};
ENDCASE => {}
END;
RETURN [baseMode]
}
ELSE {
checkout: Mode ¬ ProposedMode[field.base, lhs, FALSE, bPW];
amode: AddressMode ¬ GetAMode[checkout];
FreeMode[checkout];
IF amode#plain THEN {RETURN [Make[favoriteBitAMode]]};
IF lhs
THEN {
--make unit size as large as possible
usedPseudoUnitSz: INT;
IF field.base.bits=0
THEN usedPseudoUnitSz ¬ bPW
ELSE usedPseudoUnitSz ¬ C2CTarget.PointeeBits[MIN[field.base.bits, bPW]];
IF usedPseudoUnitSz<pseudoUnitSz THEN usedPseudoUnitSz ¬ pseudoUnitSz;
IF ((field.start MOD usedPseudoUnitSz) + var.bits)>usedPseudoUnitSz THEN RETURN [Make[favoriteBitAMode]];
RETURN [MakeMaskNShift[TRUE, usedPseudoUnitSz]]
}
ELSE {
RETURN [MakeMaskNShift[FALSE, pseudoUnitSz]];
}
}
};
value, maskNShift => {
IF lhs
THEN RETURN [Make[favoriteBitAMode]]
ELSE RETURN [MakeMaskNShift[FALSE, pseudoUnitSz]];
};
getAddr => {
IF off=0 AND unitSz=var.bits
THEN RETURN [baseMode]
ELSE {
IF lhs THEN {
??? Check this again please
IF ((field.start MOD pseudoUnitSz) + var.bits)>C2CTarget.bitsPerWord THEN RETURN [Make[favoriteBitAMode]];
RETURN [MakeMaskNShift[TRUE, pseudoUnitSz]]
};
RETURN [MakeMaskNShift[FALSE, pseudoUnitSz]];
};
};
ENDCASE => RETURN [Make[favoriteBitAMode]];
};
var.bits=0 => CantHappen;
ENDCASE => CantHappen;
};
CantHappen; RETURN [NIL];
};
ProposedModeForVar: PUBLIC PROC [var: Var, lhs: BOOL, wrongSize: BOOL, usedSz: INT] RETURNS [Mode] = {
--gets "minimal" mode with which this var can be adressed
Make: PROC [am: AddressMode] RETURNS [m: Mode ¬ NIL] = {
IF lhs THEN m ¬ SetLHS[m, TRUE];
m ¬ DSetAMode[m, am];
};
MakePlain: PROC [] RETURNS [m: Mode] = {
m ¬ Make[plain];
};
MakeVanilla: PROC [] RETURNS [m: Mode] = {
--called only when var.bits are well defined
sz1: INT ¬ C2CTarget.PointeeBits[var.bits];
IF var.bits=sz1
THEN m ¬ Make[plain]
ELSE m ¬ Make[getBitAddr];
};
baseMode: Mode;
IF var.location=nullLocation THEN CantHappen;
WITH var.location SELECT FROM
glob: GlobalVarLocation => RETURN [MakeVanilla[]];
loc: LocalVarLocation => RETURN [MakeVanilla[]];
deref: DerefLocation => {
IF usedSz>C2CTarget.bitsPerWord AND usedSz#C2CTarget.PointeeBits[usedSz] THEN RETURN [Make[favoriteBitAMode]];
IF deref.align>=C2CTarget.bestAlignment THEN RETURN [MakePlain[]];
IF deref.align>=usedSz THEN RETURN [MakePlain[]];
RETURN [Make[getBitAddr]]
};
indexed: IndexedLocation => {--var.bits are well defined [used for indexing!]
bAm: AddressMode;
IF usedSz#0 THEN usedSz ¬ C2CTarget.PointeeBits[usedSz];
baseMode ¬ ProposedMode[indexed.base, lhs, ~C2CIntCodeUtils.SizeIsProvableOk[indexed.base], usedSz];
bAm ¬ GetAMode[baseMode];
FreeMode[baseMode];
SELECT bAm FROM
getAddr, plain => {
IF var.bits=bPW THEN RETURN [Make[plain]];
IF var.bits>bPW
THEN {
IF var.bits MOD bPW # 0 THEN RETURN [Make[favoriteBitAMode]];
RETURN [Make[plain]];
}
ELSE {
IF C2CTarget.hasBytes AND var.bits=8 THEN RETURN [Make[plain]];
IF C2CTarget.hasHalfWords AND var.bits=bPHW THEN RETURN [Make[plain]];
IF usedSz MOD var.bits = 0 THEN {
unitSz: INT ¬ C2CTarget.PointeeBits[var.bits];
RETURN [MakeMaskNShift[lhs, unitSz]];
};
RETURN [Make[favoriteBitAMode]];
};
};
ENDCASE => RETURN [Make[favoriteBitAMode]];
};
field: FieldLocation => {--var.bits might be bad
RETURN [ProposedModeForField[var, lhs, wrongSize, usedSz]]
};
composite: CompositeLocation => {--var.bits are well defined
IF lhs THEN RETURN [Make[favoriteBitAMode]];
IF var.bits<bPW THEN RETURN [Make[maskNShift]];
RETURN [Make[plain]]; --currently we always generate a template
};
dummy: DummyLocation => RETURN Make[dummy];
stack: StackLocation => CantHappenCedar;
upLevel: UpLevelLocation => CantHappenCedar;
esc: EscapeLocation => CantHappenCedar;
sys: SystemLocation => CantHappenCedar;
ENDCASE => NULL;
C2CBasics.CaseMissing;
RETURN [NIL];
};
ACFromCodes: PUBLIC PROC [w: CodeOrRope, b: CodeOrRope¬NIL] RETURNS [ac: AddressContainer] = {
--converts word and bit address codes to AddressContainer
--Convention: user of container shall not use addresses more than once (dynamically)
-- to prevent doubling side effects
ac.words ¬ C2CEmit.CodeToRope[w];
ac.bits ¬ IF b=NIL THEN " 0" ELSE C2CEmit.CodeToRope[b];
};
END.