C2CAssignImpl.mesa
Copyright Ó 1987, 1988, 1989, 1990, 1991, 1993 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, 1987
Christian Jacobi, January 25, 1993 7:10 pm PST
DIRECTORY
C2CAddressing,
C2CAddressingOps,
C2CBasics,
C2CCodeUtils,
C2CDefs,
C2CEmit,
C2CIntCodeUtils,
C2CMain,
C2CMode,
C2CRunTime,
C2CSingleFloat,
C2CStateUtils,
C2CTarget,
C2CTypes,
Convert,
IntCodeDefs,
IntCodeUtils,
IO,
Rope;
C2CAssignImpl: CEDAR PROGRAM
IMPORTS C2CAddressing, C2CAddressingOps, C2CBasics, C2CCodeUtils, C2CIntCodeUtils, C2CEmit, C2CMain, C2CMode, C2CRunTime, C2CSingleFloat, C2CStateUtils, C2CTarget, C2CTypes, Convert, IntCodeUtils
EXPORTS C2CMain =
BEGIN
OPEN IntCodeDefs, C2CBasics, C2CDefs, C2CMain, C2CMode, C2CAddressing;
ROPE: TYPE = Rope.ROPE;
TemplateCode: PROC [mode: Mode] RETURNS [Code] = {
RETURN [ C2CEmit.IdentCode[GetTemplate[mode]] ]
};
Cat2: PROC [c1, c2: Code] RETURNS [c: Code] = {
IF c2=NIL THEN RETURN [c1];
IF c1=NIL THEN RETURN [c2];
RETURN [C2CEmit.Cat[c1, c2]]
};
AssBitsFromPlainOrValueToPlainCommonCase: PROC [ccIn: CodeCont, reqMode: Mode, assignNode: AssignNode, lcc, rcc: CodeCont] RETURNS [cc: CodeCont] = {
requiredMode=assBits; lhsMode=plain, rhMode={plain|value}
destBits: INT ¬ ContainerSize[reqMode];
tSz: INT ¬ C2CTarget.TemporaryBits[assignNode.rhs.bits];
ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[reqMode];
IF destBits=0 THEN NotYetImpl;
cc ¬ ccIn;
IF C2CIntCodeUtils.UseTemporaryIfReused[assignNode.rhs]
THEN {
temp: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, tSz, "tmp"];
cc.sc ¬ C2CEmit.Cat[cc.sc, temp, " = (", C2CEmit.nestNLine, lcc.ec];
cc.sc ¬ C2CEmit.Cat[cc.sc, " = ", rcc.ec, "\n);", C2CEmit.unNestNLine];
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: C2CEmit.IdentCode[temp], ac: ac, destBits: destBits, tempBits: tSz];
}
ELSE {
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", C2CEmit.CopyC[rcc.ec], ";\n"];
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: rcc.ec, ac: ac, destBits: destBits, tempBits: C2CTarget.PointeeBits[assignNode.rhs.bits]];
};
};
GenNodeNDefault: PROC [node: Node, mode: Mode] RETURNS [cc: CodeCont] = {
cc ¬ GenNode[node, mode];
IF cc.ec#NIL AND node.bits<=C2CTarget.bitsPerWord THEN {
at: IntCodeDefs.ArithClass ¬ C2CEmit.GetArithClass[cc.ec];
SELECT at.kind FROM
address => cc.ec ¬ C2CEmit.CastWord[cc.ec];
ENDCASE => {}
};
};
AssGenPlainToPlain: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont] = {
Using plain for lh and rh.
plain, therefore: NOT StatementCodeX[deep: FALSE].
lcc, rcc: CodeCont;
reqAM: AddressMode ¬ GetAMode[reqMode];
IF assignNode.lhs.bits#C2CTarget.PointeeBits[assignNode.lhs.bits] THEN CantHappen;
--plain should have the right number of bits..?
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
cc.sc ¬ lcc.sc;
rcc ¬ GenNodeNDefault[node: assignNode.rhs, mode: rhPropMode];
cc.sc ¬ Cat2[cc.sc, rcc.sc];
IF rcc.ec#NIL THEN rcc.ec ¬ C2CEmit.MinPrecedence[rcc.ec, unaryPrecedence];
SELECT reqAM FROM
skip => {
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", rcc.ec, ";\n"];
};
value, plain, maskNShift => {
cc.ec ¬ C2CEmit.Cat[lcc.ec, " = ", rcc.ec];
cc.ec ¬ C2CEmit.ParentizeAndLn[cc.ec];
};
assBitAddr, assAddr => {
addr: ROPE;
SELECT reqAM FROM
assBitAddr => {
ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[reqMode];
addr ¬ ac.words;
cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = 0;\n"];--no adjustment since rhs plain mode
};
assAddr => {
addr ¬ GetTemplate[reqMode];
};
ENDCASE => CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc,
addr, " = ", C2CEmit.TakeAddr[C2CEmit.CopyC[rcc.ec]], ";\n"
];
IF C2CIntCodeUtils.UseTemporaryIfReused[assignNode.rhs]
THEN {
cc.sc ¬ C2CEmit.Cat[cc.sc,
lcc.ec, " = ",
C2CEmit.Deref[C2CEmit.IdentCode[addr], assignNode.rhs.bits], ";\n"
];
}
ELSE {
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", rcc.ec, ";\n"];
};
};
getBitAddr, getAddr => {
IF C2CIntCodeUtils.UseTemporaryIfReused[assignNode.rhs, TRUE]
THEN {
tmpAddr: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "taddr"];
cc.ec ¬ C2CEmit.Cat[
C2CEmit.Cat[tmpAddr, " = ", C2CEmit.TakeAddr[rcc.ec], ",\n"],
C2CEmit.Cat[lcc.ec, " = ", C2CEmit.Deref[C2CEmit.IdentCode[tmpAddr], assignNode.rhs.bits], ",\n"],
tmpAddr, "\n"
];
}
ELSE {
cc.ec ¬ C2CEmit.Cat[lcc.ec, " = ", C2CEmit.CopyC[rcc.ec], ",\n"];
cc.ec ¬ C2CEmit.Cat[cc.ec, C2CEmit.TakeAddr[rcc.ec, TRUE], "\n"];
};
cc.ec ¬ C2CEmit.ParentizeAndLn[cc.ec];
cc.xbc ¬ NIL; --no adjustment since rhs plain mode
};
assUnits => {
cont: ROPE ¬ GetTemplate[reqMode];
cc.sc ¬ C2CEmit.Cat[cc.sc, cont, " = (", C2CEmit.nestNLine, lcc.ec];
cc.sc ¬ C2CEmit.Cat[cc.sc, " = ", rcc.ec, "\n);", C2CEmit.unNestNLine];
};
assBits => {
cc ¬ AssBitsFromPlainOrValueToPlainCommonCase[ccIn: cc, reqMode: reqMode, assignNode: assignNode, lcc: lcc, rcc: rcc];
};
ENDCASE => CaseMissing;
};
AssGenValueToPlain: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont] = {
Using plain for lh
plain, value, therefore: NOT StatementCodeX[deep: FALSE].
lcc, rcc: CodeCont;
reqAM: AddressMode ¬ GetAMode[reqMode];
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
cc.sc ¬ lcc.sc;
rcc ¬ GenNodeNDefault[node: assignNode.rhs, mode: SetAMode[rhPropMode, value]];
cc.sc ¬ Cat2[cc.sc, rcc.sc];
IF rcc.ec=NIL THEN CantHappen;
rcc.ec ¬ C2CEmit.MinPrecedence[rcc.ec, unaryPrecedence];
SELECT reqAM FROM
skip => {
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", rcc.ec, ";\n"];
};
value, plain, maskNShift => {
cc.ec ¬ C2CEmit.Cat[lcc.ec, " = ", rcc.ec];
cc.ec ¬ C2CEmit.ParentizeAndLn[cc.ec];
};
assAddr => CantHappen;
assBitAddr => {
addr: ROPE;
sz: INT ¬ C2CTarget.TemporaryBits[assignNode.rhs.bits];
tmp: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, sz, "tmp"];
SELECT reqAM FROM
assBitAddr => {
ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[reqMode];
addr ¬ ac.words;
--template is right adjusted
cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = ", Convert.RopeFromInt[sz-assignNode.rhs.bits], ";\n"];
};
XXX assAddr => {addr ← GetTemplate[reqMode]};
ENDCASE => CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, tmp, " = (", C2CEmit.nestNLine, lcc.ec];
cc.sc ¬ C2CEmit.Cat[cc.sc, " = ", rcc.ec, ");", C2CEmit.unNestNLine];
cc.sc ¬ C2CEmit.Cat[cc.sc, addr, " = (word) &", tmp, ";\n"];
};
getAddr => CantHappen;
getBitAddr => {
sz: INT ¬ C2CTarget.TemporaryBits[assignNode.rhs.bits];
tmp: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, sz, "tmp"];
cc.ec ¬ C2CEmit.Cat[tmp, " = (", C2CEmit.nestNLine, lcc.ec];
cc.ec ¬ C2CEmit.Cat[cc.ec, " = ", rcc.ec, "),", C2CEmit.unNestNLine];
cc.ec ¬ C2CEmit.Cat[cc.ec, "&", tmp];
cc.ec ¬ C2CEmit.ParentizeAndLn[cc.ec];
cc.xbc ¬ NIL;
IF sz>assignNode.rhs.bits THEN
--template is right adjusted
cc.xbc ¬ C2CCodeUtils.ConstI[sz-assignNode.rhs.bits]; --positive
};
assUnits => {
cont: ROPE ¬ GetTemplate[reqMode];
cc.sc ¬ C2CEmit.Cat[cc.sc, cont, " = (", C2CEmit.nestNLine, lcc.ec];
cc.sc ¬ C2CEmit.Cat[cc.sc, " = ", rcc.ec, "\n);", C2CEmit.unNestNLine];
};
assBits => {
cc ¬ AssBitsFromPlainOrValueToPlainCommonCase[ccIn: cc, reqMode: reqMode, assignNode: assignNode, lcc: lcc, rcc: rcc];
};
ENDCASE => CaseMissing;
};
MakeUpAdrContainer: PROC [lhPropMode: Mode] RETURNS [Mode] = {
--declares an address container and sets the templates
SELECT GetAMode[lhPropMode] FROM
plain, getAddr, getBitAddr, dummy => {};
assAddr => {
template: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "adr"];
lhPropMode ¬ SetTemplate[lhPropMode, template];
};
assBitAddr => {
ac: AddressContainer ¬ C2CStateUtils.ANewBitAddress[];
lhPropMode ¬ SetAddrContainer[lhPropMode, ac];
};
ENDCASE => CaseMissing;
RETURN [lhPropMode]
};
GenBitAddressed: PROC [node: Node, proposedMode: Mode, sCIn: Code¬NIL] RETURNS [cc: CodeCont] = {
--code for address is returned in ec and xbc
--Mainly used for LHS [but not exclusively]
--Makes up addr containers if necessary
--proposedMode: for node, not necessarily Bit Addressed
SELECT GetAMode[proposedMode] FROM
plain => {
cc ¬ GenNode[node, proposedMode];
cc.ec ¬ C2CEmit.TakeAddr[cc.ec, TRUE];
};
getAddr, getBitAddr => {
cc ¬ GenNode[node, proposedMode];
};
assAddr => {
template: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "adr"];
proposedMode ¬ SetTemplate[proposedMode, template];
cc ¬ GenNode[node, proposedMode];
IF cc.ec#NIL THEN CantHappen;
cc.ec ¬ C2CEmit.IdentCode[template];
cc.ec ¬ C2CEmit.SetAddressable[cc.ec, FALSE];
};
assBitAddr => {
ac: AddressContainer ¬ C2CStateUtils.ANewBitAddress[];
proposedMode ¬ SetAddrContainer[proposedMode, ac];
cc ¬ GenNode[node, proposedMode];
IF cc.ec#NIL OR cc.xbc#NIL THEN CantHappen;
cc.ec ¬ C2CEmit.IdentCode[ac.words];
cc.ec ¬ C2CEmit.SetAddressable[cc.ec, FALSE];
cc.xbc ¬ C2CEmit.IdentCode[ac.bits];
};
ENDCASE => CaseMissing;
cc.sc ¬ Cat2[sCIn, cc.sc];
};
MoveToBitAddress: PROC [propMode: Mode, cc: CodeCont, node: Node] RETURNS [CodeCont] = {
--generates code to move the node into a destination specified with a bit address
--code for address is found in cc.ec and cc.xbc
-- node.bits>bitsPerWord ! [Not conceptionally; simply restricted implementation]
--propMode: of node
propAM: C2CAddressing.AddressMode ¬ GetAMode[propMode];
wC: Code ¬ cc.ec;
bC: Code ¬ cc.xbc;
sourceIsWordAddressed: BOOL ¬
SELECT propAM FROM
plain, getAddr, assAddr => TRUE,
ENDCASE => FALSE;
IF cc.ec=NIL THEN CantHappen;
cc.ec ¬ cc.xbc ¬ NIL;
SELECT propAM FROM
plain, getAddr, getBitAddr, assAddr, assBitAddr => {
acl, acr: AddressContainer;
rcc: CodeCont ¬ GenBitAddressed[node, propMode];
cc.sc ¬ Cat2[cc.sc, rcc.sc];
SELECT TRUE FROM
sourceIsWordAddressed AND bC=NIL AND rcc.xbc=NIL AND node.bits MOD C2CTarget.bitsPerWord=0 => {
cc.sc ¬ C2CEmit.Cat[cc.sc,
C2CRunTime.MoveWords[dst: wC, src: rcc.ec, nWords: node.bits/C2CTarget.bitsPerWord],
";\n"
];
};
bC=NIL AND rcc.xbc=NIL AND (node.bits MOD 8) = 0 AND C2CTarget.hasBytes => {
cc.sc ¬ C2CEmit.Cat[cc.sc,
--Disjoint not wrong, but general case would be better
C2CRunTime.MoveBytesDisjoint[dst: wC, src: rcc.ec, nBytes: node.bits/8],
";\n"
];
};
ENDCASE => {
acl ¬ ACFromCodes[wC, bC];
acr ¬ ACFromCodes[rcc.ec, rcc.xbc];
cc.sc ¬ C2CEmit.Cat[cc.sc,
C2CRunTime.MoveField[dst: acl, src: acr, bits: node.bits],
";\n"
];
};
};
assBits => {
ac: AddressContainer ¬ ACFromCodes[wC, bC];
propMode ¬ SetAddrContainer[propMode, ac];
cc ¬ GenNode[node, propMode];
};
dummy => {
ac: AddressContainer ¬ ACFromCodes[wC, bC];
c: Code ¬ C2CRunTime.FillFields[dst: ac, bits: 1, times: node.bits, value: C2CCodeUtils.ConstC[0]];
cc.sc ¬ C2CEmit.Cat[cc.sc, c, ";\n"];
};
ENDCASE => CaseMissing;
RETURN [cc];
};
CertainlyREAL: PROC [n: Node] RETURNS [certainly: BOOL ¬ FALSE] = {
IF n.bits#C2CTarget.bitsPerWord THEN RETURN;
WITH n SELECT FROM
applyNode: ApplyNode =>
WITH applyNode.proc SELECT FROM
operNode: OperNode =>
WITH operNode.oper SELECT FROM
arithOp: ArithOper =>
IF arithOp.class.precision=C2CTarget.bitsPerWord AND arithOp.class.kind=real THEN
SELECT arithOp.select FROM
add, sub, mul, div, mod, neg => RETURN [TRUE];
ENDCASE => {};
ENDCASE => {};
ENDCASE => {};
ENDCASE => {};
};
SetTemplateForlHSMaskNShift: PROC [lHSMaskNShiftMode: Mode, template: CodeOrRope, assign: AssignNode] RETURNS [mode: Mode] = {
doMask: BOOL ¬ TRUE;
IF assign.rhs.bits#assign.lhs.bits THEN CantHappen;
--find out whether masking right hand side can be ommited: doMask
WITH assign.rhs SELECT FROM
var: Var =>
WITH var.location SELECT FROM
field: FieldLocation => doMask ¬ FALSE;
indexed: IndexedLocation => doMask ¬ FALSE;
deref: DerefLocation => doMask ¬ FALSE;
dummy: DummyLocation => doMask ¬ FALSE;
comp: CompositeLocation => doMask ¬ FALSE;
ENDCASE => doMask ¬ TRUE;
const: ConstNode =>
WITH const SELECT FROM
wc: WordConstNode => doMask ¬ HasLeftBitSet[wc.word, IntCodeDefs.bitsPerWord-assign.rhs.bits];
ENDCASE => doMask ¬ TRUE;
apply: ApplyNode =>
WITH apply.proc SELECT FROM
oper: OperNode =>
WITH oper.oper SELECT FROM
bool: BooleanOper => doMask ¬ bool.bits>1 OR bool.class=xor;
comp: CompareOper => doMask ¬ FALSE;
convert: ConvertOper => doMask ¬ FALSE;
check: CheckOper => {
IF check.sense=lt THEN {
isConst: BOOL; limWord: Word; constVal: CARD ¬ 0;
[isConst, constVal] ¬ C2CIntCodeUtils.IsSimpleConst[apply.args.rest.first];
IF isConst AND constVal>0 THEN {
limWord ¬ IntCodeUtils.CardToWord[constVal-1];
IF ~HasLeftBitSet[limWord, IntCodeDefs.bitsPerWord-assign.rhs.bits] THEN {
doMask ¬ FALSE;
};
};
};
};
ENDCASE => doMask ¬ TRUE;
ENDCASE => doMask ¬ TRUE;
ENDCASE => doMask ¬ TRUE;
IF doMask THEN {
template ¬ C2CEmit.Cat[C2CCodeUtils.Mask[assign.rhs.bits], " & (", template, ")"];
};
template ¬ C2CEmit.Parentize[template];
mode ¬ C2CMode.SetTemplate[lHSMaskNShiftMode, C2CEmit.CodeToRopeD[template]];
mode ¬ C2CMode.SetLHSMaskNShiftNode[mode, assign.rhs];
};
HasLeftBitSet: PROC [limWord: Word, leftBits: INT] RETURNS [BOOL ¬ FALSE] = {
FOR b: INT IN [0..leftBits+IntCodeDefs.bitsPerWord-C2CTarget.bitsPerWord) DO
IF limWord[b] THEN RETURN [TRUE];
ENDLOOP
};
AssGenIfSkipRequested: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont] = {
lcc, rcc: CodeCont;
rhAM: AddressMode ¬ GetAMode[rhPropMode];
lhAM: AddressMode ¬ GetAMode[lhPropMode];
IF assignNode.rhs.bits<=C2CTarget.bitsPerWord
THEN {
--optimization for the simple case using REAL (float)
BEGIN
cc1: CodeCont; done: BOOL;
[cc1, done] ¬ TryAssignWithFloatingType[assignNode, reqMode, lhPropMode];
IF done THEN RETURN [cc1];
END;
cc ¬ C2CAddressingOps.LoadArithNode[assignNode.rhs];
cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, unaryPrecedence];
IF lhAM=lHSMaskNShift
THEN {
lhPropMode ¬ SetTemplateForlHSMaskNShift[lhPropMode, cc.ec, assignNode];
cc.ec ¬ NIL
}
ELSE {
lhPropMode ¬ MakeUpAdrContainer[lhPropMode];
};
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
cc.sc ¬ Cat2[cc.sc, lcc.sc];
IF lcc.ec#NIL THEN lcc.ec ¬ C2CEmit.MinPrecedence[lcc.ec, unaryPrecedence];
SELECT lhAM FROM
plain => {
IF lcc.ec=NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", cc.ec, ";\n"];
cc.ec ¬ NIL;
};
getAddr => {
IF lcc.ec=NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, C2CEmit.Deref[lcc.ec, assignNode.rhs.bits], " = ", cc.ec, ";\n"];
cc.ec ¬ NIL;
};
assAddr => {
IF lcc.ec#NIL THEN CantHappen;
lcc.ec ¬ C2CEmit.Deref[TemplateCode[lhPropMode], assignNode.rhs.bits];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", cc.ec, ";\n"];
cc.ec ¬ NIL;
};
assBitAddr => {
IF lcc.ec#NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc,
C2CRunTime.DepositField[dst: GetAddrContainer[lhPropMode], bits: assignNode.lhs.bits, word: cc.ec],
";\n"
];
cc.ec ¬ NIL;
};
getBitAddr => {
ac: AddressContainer ¬ ACFromCodes[lcc.ec, lcc.xbc];
IF lcc.ec=NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc,
C2CRunTime.DepositField[dst: ac, bits: assignNode.lhs.bits, word: cc.ec],
";\n"
];
cc.ec ¬ NIL;
};
dummy => {
IF cc.ec#NIL THEN
cc.sc ¬ C2CEmit.Cat[cc.sc, " (void) ", cc.ec, ";\n"];
cc.ec ¬ NIL;
};
lHSMaskNShift => {IF lcc.ec#NIL THEN CantHappen};
ENDCASE => CaseMissing;
}
ELSE {
SELECT lhAM FROM
plain => {
SELECT rhAM FROM
plain, dummy =>
cc ¬ AssGenValueToPlain[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
value, maskNShift =>
cc ¬ AssGenValueToPlain[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
assUnits =>
cc ¬ AssignForAssUnitsToPlain[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
skip => CantHappen;
getAddr => {
lcc ¬ GenNode[assignNode.lhs, lhPropMode];
rcc ¬ GenNode[assignNode.rhs, rhPropMode];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.sc, rcc.sc];
IF lcc.ec=NIL OR rcc.ec=NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", C2CEmit.Deref[rcc.ec, assignNode.rhs.bits], ";\n"];
cc.ec ¬ NIL;
};
assBitAddr, getBitAddr, assBits, assAddr, getAddr => {
cc ¬ GenBitAddressed[assignNode.lhs, lhPropMode, cc.sc];
cc ¬ MoveToBitAddress[rhPropMode, cc, assignNode.rhs];
};
ENDCASE => CaseMissing;
};
assBitAddr, getBitAddr, assAddr, getAddr => {
cc ¬ GenBitAddressed[assignNode.lhs, lhPropMode, cc.sc];
cc ¬ MoveToBitAddress[rhPropMode, cc, assignNode.rhs];
};
dummy => {
rhPropMode ¬ MakeUpAdrContainer[rhPropMode];
SELECT rhAM FROM
dummy => RETURN;
getAddr, plain, getBitAddr, value, maskNShift => {
cc ¬ GenNodeNDefault[assignNode.rhs, rhPropMode];
IF cc.ec#NIL THEN
cc.sc ¬ C2CEmit.Cat[cc.sc, " (void) ", cc.ec, ";\n"];
IF cc.xbc#NIL THEN
cc.sc ¬ C2CEmit.Cat[cc.sc, " (void) ", cc.xbc, ";\n"];
cc.ec ¬ cc.xbc ¬ NIL;
};
ENDCASE => CaseMissing;
};
lHSMaskNShift => CantHappen;
ENDCASE => CaseMissing;
};
};
AssGenWorstCase: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont] = {
--May be inefficient but is not used very often
--make a temporary, assign the rhs into the temporary and then use the temporary
--to make both, the lhs and the required result
MakeRhs: PROC [] RETURNS [Code] = {
RETURN [ C2CEmit.Cat[" = (", C2CTypes.DefineType[tempBits], ") ", tempName, ";\n"] ];
};
lcc: CodeCont;
tempBits: INT ¬ C2CTarget.TemporaryBits[assignNode.rhs.bits];
lhAM: AddressMode ¬ GetAMode[lhPropMode];
rqAM: AddressMode ¬ GetAMode[reqMode];
tempName: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, tempBits];
cc ¬ GenNodeNDefault[assignNode.rhs, DSetBaseSize[SetAssUnits[NIL, tempName, tempBits], tempBits]]; --right adjusted
IF cc.ec#NIL THEN CantHappen;
IF lhAM=lHSMaskNShift
THEN lhPropMode ¬ SetTemplateForlHSMaskNShift[lhPropMode, tempName, assignNode]
ELSE lhPropMode ¬ MakeUpAdrContainer[lhPropMode];
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
cc.sc ¬ Cat2[cc.sc, lcc.sc];
SELECT lhAM FROM
plain => {
IF lcc.ec=NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, MakeRhs[]];
};
getAddr => {
IF lcc.ec=NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, C2CEmit.Deref[lcc.ec, assignNode.lhs.bits], MakeRhs[]];
};
assAddr => {
IF lcc.ec#NIL THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, C2CEmit.Deref[TemplateCode[lhPropMode], assignNode.lhs.bits], MakeRhs[]];
};
assBitAddr => {
IF lcc.ec#NIL THEN CantHappen;
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: C2CEmit.IdentCode[tempName], ac: GetAddrContainer[lhPropMode], destBits: assignNode.rhs.bits, tempBits: tempBits];
};
getBitAddr => {
ac: AddressContainer ¬ ACFromCodes[lcc.ec, lcc.xbc];
IF lcc.ec=NIL THEN CantHappen;
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: C2CEmit.IdentCode[tempName], ac: ac, destBits: assignNode.rhs.bits, tempBits: tempBits];
};
lHSMaskNShift => {
IF lcc.ec#NIL THEN CantHappen;
IF assignNode.lhs.bits>C2CTarget.bitsPerWord THEN CantHappen;
};
ENDCASE => CaseMissing;
cc.ec ¬ NIL;
SELECT rqAM FROM
skip => {};
plain, value, maskNShift => {cc.ec ¬ C2CEmit.IdentCode[tempName]};
getAddr => {
NotYetImpl; --??? here we should consider alignment of usefull data in template
cc.ec ¬ C2CEmit.TakeAddr[C2CEmit.IdentCode[tempName], TRUE]
};
assAddr => {
NotYetImpl; --??? here we should consider alignment of usefull data in template
cc.sc ¬ C2CEmit.Cat[cc.sc, GetTemplate[lhPropMode], " = (word) &", tempName, ";\n"];
};
assUnits => {
cc.sc ¬ C2CEmit.Cat[cc.sc, GetTemplate[lhPropMode], " = ", tempName, ";\n"];
};
assBitAddr => {
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: C2CEmit.IdentCode[tempName], ac: GetAddrContainer[lhPropMode], destBits: assignNode.rhs.bits, tempBits: tempBits];
};
getBitAddr => {
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: C2CEmit.IdentCode[tempName], ac: [tempName, " 0"], destBits: assignNode.rhs.bits, tempBits: tempBits];
};
ENDCASE => CaseMissing;
};
SpecialCaseAssignComposite: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont] = {
IF GetAMode[reqMode]#skip THEN CantHappen;
IF GetAMode[lhPropMode]#plain THEN CantHappen;
IF assignNode.rhs.bits<=C2CTarget.bitsPerWord THEN CantHappen;
WITH assignNode.rhs SELECT FROM
var: Var =>
WITH var.location SELECT FROM
composite: CompositeLocation => {
hackAddr: ROPE;
lcc: CodeCont ¬ GenNode[node: assignNode.lhs, mode: lhPropMode];
lcc.ec ¬ C2CEmit.TakeAddr[lcc.ec];
IF C2CIntCodeUtils.UseTemporaryIfReused[assignNode.lhs, TRUE]
THEN {
hackAddr ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "tmpAddr"];
lcc.sc ¬ C2CEmit.Cat[lcc.sc, hackAddr, " = ", lcc.ec, ";\n"];
}
ELSE hackAddr ¬ C2CEmit.CodeToRopeD[lcc.ec];
reqMode ¬ SetExpr[reqMode, TRUE];
cc ¬ C2CMain.HandleCompositeLoc[varNode: var, mode: reqMode, compositeLoc: composite, hackAddr: hackAddr];
cc.sc ¬ Cat2[lcc.sc, cc.sc];
};
ENDCASE => CantHappen;
ENDCASE => CantHappen;
};
AssignForAssUnitsToPlain: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont] = {
Using plain for lh, AssUnits for rhs; all modes for reqMode
template: ROPE; --will be right adjusted
tSz: INT ¬ C2CTarget.TemporaryBits[assignNode.rhs.bits];
delayed: BOOL ¬ FALSE;
lcc, rcc: CodeCont;
reqAM: AddressMode ¬ GetAMode[reqMode];
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
lcc.ec ¬ C2CEmit.MinPrecedence[lcc.ec, unaryPrecedence];
cc.sc ¬ lcc.sc;
SELECT reqAM FROM
skip => template ¬ C2CEmit.CodeToRopeD[lcc.ec];--assume #bits ok
plain => CantHappen;
assAddr, getAddr => CantHappen;
value, maskNShift, assBitAddr, getBitAddr, assUnits, assBits => {
template ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, tSz, "tmp"];
delayed ¬ TRUE;
};
ENDCASE => ERROR CaseMissing;
rhPropMode ¬ SetTemplate[rhPropMode, template];
rhPropMode ¬ SetContainerSize[rhPropMode, tSz];
rcc ¬ GenNode[node: assignNode.rhs, mode: rhPropMode];
cc.sc ¬ Cat2[cc.sc, rcc.sc];
SELECT reqAM FROM
skip => {IF rcc.ec#NIL THEN CantHappen};
plain => CantHappen;
value, maskNShift => {
cc.ec ¬ C2CEmit.Cat[lcc.ec, " = ", template];
cc.ec ¬ C2CEmit.ParentizeAndLn[cc.ec];
};
assAddr => CantHappen;
assBitAddr => {
ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[reqMode];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", template, ";\n"];
cc.sc ¬ C2CEmit.Cat[cc.sc, ac.words, " = (word) &", template, ";\n"];
cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = ", Convert.RopeFromInt[tSz-assignNode.rhs.bits], ";\n"];--template is right adjusted
};
getAddr => CantHappen;
getBitAddr => {
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", template, ";\n"];
IF tSz=assignNode.rhs.bits
THEN cc.xbc ¬ NIL
ELSE cc.xbc ¬ C2CCodeUtils.ConstI[tSz-assignNode.rhs.bits]; --adjustment! positive!
cc.ec ¬ C2CEmit.Cat["&", template];
cc.ec ¬ C2CEmit.SetPrecedence[cc.ec, unaryPrecedence];
};
assUnits => {
rqTmp: ROPE ¬ GetTemplate[reqMode];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", template, ";\n"];
cc.sc ¬ C2CEmit.Cat[cc.sc, rqTmp, " = ", template, ";\n"];
};
assBits => {
cSz: INT ¬ ContainerSize[reqMode];
IF cSz#assignNode.rhs.bits THEN CantHappen;
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", template, ";\n"];
cc ¬ MoveTemporaryToAssBitsX[inCC: cc, tmpC: C2CEmit.IdentCode[template], ac: GetAddrContainer[reqMode], destBits: cSz, tempBits: tSz];
};
ENDCASE => CaseMissing;
};
MoveTemporaryToAssBitsX: PROC [inCC: CodeCont, tmpC: Code, ac: C2CAddressing.AddressContainer, destBits, tempBits: INT] RETURNS [cc: CodeCont] = {
--generates code to assign the rightmost destBits in a temporary of size tempBits into ac
IF destBits=0 OR tempBits=0 THEN ERROR NotYetImpl;
IF destBits>tempBits THEN CantHappen;
IF tempBits#C2CTarget.PointeeBits[tempBits] THEN CantHappen;
cc ¬ inCC;
IF tempBits <= C2CTarget.bitsPerWord
THEN {
cc.sc ¬ C2CEmit.Cat[cc.sc,
C2CRunTime.DepositField[dst: ac, bits: destBits, word: tmpC],
";\n"
];
}
ELSE {
offC: Code ¬ IF tempBits=destBits THEN NIL ELSE C2CCodeUtils.ConstC[tempBits-destBits];
cc.sc ¬ C2CEmit.Cat[cc.sc,
C2CRunTime.MoveField[dst: ac, bits: destBits,
src: ACFromCodes[C2CEmit.TakeAddr[tmpC, TRUE], offC]
],
";\n"
];
};
};
RefineJumps: PROC [m: Mode, node: Node] RETURNS [Mode] = {
--changes mode if mode not feasible because of block assignments
IF node.bits=0 THEN NotYetImpl;
IF C2CIntCodeUtils.StatementJumps[node] THEN {
m ¬ SetExpr[m, FALSE];
SELECT GetAMode[m] FROM
dummy, skip, assBitAddr, assAddr, assUnits, assBits, bad => {};
maskNShift, value, plain => {
m ¬ SetAMode[m, assUnits];
m ¬ SetContainerSize[m, C2CTarget.TemporaryBits[node.bits]];
};
getBitAddr => {
m ¬ SetAMode[m, assBitAddr];
};
getAddr => {
m ¬ SetAMode[m, assAddr];
};
ENDCASE => m ¬ SetAMode[m, bad];
};
RETURN [m];
};
GenAssignNode: PUBLIC PROC [assignNode: AssignNode, mode: Mode] RETURNS [cc: CodeCont] = {
reqMode: Mode ¬ mode;
lhPropMode: Mode ¬ C2CAddressing.ProposedModeForVar[assignNode.lhs, TRUE, FALSE, assignNode.lhs.bits];
rhPropMode: Mode ¬ C2CAddressing.ProposedMode[assignNode.rhs, FALSE, FALSE, assignNode.rhs.bits];
reqAMode: AddressMode ¬ GetAMode[reqMode];
lhPropAMode: AddressMode ¬ GetAMode[lhPropMode];
IF assignNode.lhs.bits#assignNode.rhs.bits THEN CantHappen;
lhPropMode ¬ DSetBaseSize[lhPropMode, assignNode.lhs.bits];
rhPropMode ¬ DSetBaseSize[rhPropMode, assignNode.rhs.bits];
--take some easy cases first...
rhPropMode ¬ RefineJumps[rhPropMode, assignNode.rhs];
SELECT lhPropAMode FROM
plain => {
IF reqAMode=skip AND assignNode.rhs.bits>C2CTarget.bitsPerWord THEN
WITH assignNode.rhs SELECT FROM
var: Var =>
WITH var.location SELECT FROM
composite: CompositeLocation=> {
cc ¬ SpecialCaseAssignComposite[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
RETURN;
};
ENDCASE => {};
app: ApplyNode =>
WITH app.proc SELECT FROM
op: OperNode =>
WITH op.oper SELECT FROM
mesaOper: MesaOper =>
IF mesaOper.mesa=all AND app.bits>C2CTarget.bitsPerWord AND C2CTarget.TemporaryBits[app.bits]=app.bits THEN {
rhPropMode ¬ SetAMode[rhPropMode, assUnits];
};
ENDCASE => {};
ENDCASE => {};
ENDCASE => {};
--optimization for the simple case using REAL (float)
IF assignNode.lhs.bits=C2CTarget.bitsPerWord THEN {
cc1: CodeCont; done: BOOL;
[cc1, done] ¬ TryAssignWithFloatingType[assignNode, reqMode, lhPropMode];
IF done THEN {
FreeMode[lhPropMode];
FreeMode[rhPropMode];
RETURN [cc1];
};
};
--optimization for the simple case using partwords
IF assignNode.lhs.bits=C2CTarget.bitsPerHalfWord OR assignNode.lhs.bits=8 THEN {
cc1: CodeCont; done: BOOL;
[cc1, done] ¬ TryAssignPartWords[assignNode, reqMode, lhPropMode, rhPropMode];
IF done THEN {
FreeMode[lhPropMode];
FreeMode[rhPropMode];
RETURN [cc1];
};
};
SELECT GetAMode[rhPropMode] FROM
plain => {
cc ¬ AssGenPlainToPlain[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
FreeMode[lhPropMode]; FreeMode[rhPropMode];
RETURN;
};
value, maskNShift => {
cc ¬ AssGenValueToPlain[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
FreeMode[lhPropMode]; FreeMode[rhPropMode];
RETURN;
};
assUnits => {
cc ¬ AssignForAssUnitsToPlain[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
FreeMode[lhPropMode]; FreeMode[rhPropMode];
RETURN;
};
ENDCASE => {};
};
ENDCASE => {};
SELECT reqAMode FROM
skip => {
cc ¬ AssGenIfSkipRequested[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
};
ENDCASE => {
cc ¬ AssGenWorstCase[assignNode: assignNode, reqMode: reqMode, lhPropMode: lhPropMode, rhPropMode: rhPropMode];
};
FreeMode[lhPropMode];
FreeMode[rhPropMode];
};
TryAssignPartWords: PROC [assignNode: AssignNode, reqMode, lhPropMode, rhPropMode: Mode] RETURNS [cc: CodeCont, done: BOOL ¬ FALSE] = {
--try optimization for the simple case using part words
--get rid of masking in case where simple assignment would be correct anyway
SELECT TRUE FROM
assignNode.lhs.bits=C2CTarget.bitsPerHalfWord AND C2CTarget.hasHalfWords => {};
assignNode.lhs.bits=8 AND C2CTarget.hasBytes => {};
ENDCASE => RETURN;
IF GetAMode[reqMode]#skip THEN RETURN;
SELECT GetAMode[rhPropMode] FROM
plain, value, maskNShift => {};
ENDCASE => RETURN;
SELECT GetAMode[lhPropMode] FROM
plain => {};
ENDCASE => RETURN;
WITH assignNode.lhs SELECT FROM
var: Var =>
WITH var.location SELECT FROM
field: FieldLocation => {};
deref: DerefLocation => {};
indexed: IndexedLocation => {};
ENDCASE => RETURN;
ENDCASE => RETURN;
WITH assignNode.rhs SELECT FROM
var: Var =>
WITH var.location SELECT FROM
field: FieldLocation => IF (field.start+assignNode.rhs.bits)=C2CTarget.bitsPerWord THEN {
lcc, rcc: CodeCont;
IF field.base.bits=C2CTarget.bitsPerWord AND C2CIntCodeUtils.SizeIsProvableOk[field.base] THEN {
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
rcc ¬ C2CAddressingOps.LoadArithNode[field.base]; --The base itself!!!
lcc.ec ¬ C2CEmit.MinPrecedence[lcc.ec, assignPrecedence];
rcc.ec ¬ C2CEmit.MinPrecedence[rcc.ec, assignPrecedence];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.sc, rcc.sc];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", rcc.ec, ";\n"];
cc.ec ¬ NIL;
RETURN [cc, TRUE];
};
};
ENDCASE => {}
ENDCASE => {}
};
TryAssignWithFloatingType: PROC [assignNode: AssignNode, reqMode, lhPropMode: Mode] RETURNS [cc: CodeCont, done: BOOL ¬ FALSE] = {
--try optimization for the simple case using REAL (float)
IF GetAMode[reqMode]#skip THEN RETURN;
IF assignNode.lhs.bits#C2CTarget.bitsPerWord THEN RETURN;
IF C2CSingleFloat.GoodToUseFloatType[assignNode.rhs] AND C2CSingleFloat.UseInline[] THEN {
lcc, rcc: CodeCont;
lhAM: AddressMode ¬ GetAMode[lhPropMode];
SELECT lhAM FROM
plain, getAddr => {
lcc ¬ GenVarNode[varNode: assignNode.lhs, mode: lhPropMode];
lcc.ec ¬ C2CEmit.MinPrecedence[lcc.ec, unaryPrecedence];
SELECT lhAM FROM
plain => lcc.ec ¬ C2CEmit.Cat["*(float*)", C2CEmit.TakeAddr[lcc.ec, TRUE]];
getAddr => lcc.ec ¬ C2CEmit.Cat["*(float*)", lcc.ec];
ENDCASE => ERROR;
rcc ¬ C2CSingleFloat.LoadAsFloat[assignNode.rhs];
rcc.ec ¬ C2CEmit.MinPrecedence[rcc.ec, assignPrecedence];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.sc, rcc.sc];
cc.sc ¬ C2CEmit.Cat[cc.sc, lcc.ec, " = ", rcc.ec, ";\n"];
cc.ec ¬ NIL;
RETURN [cc, TRUE];
};
ENDCASE => {}
};
};
END.