<<>> <> <> <> <> 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] = { <> 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] = { <> <> 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] = { <> <> 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"]; }; < {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] = { <> 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.