DIRECTORY C2CAddressing, C2CAddressingOps, C2CBasics, C2CCodeUtils, C2CDefs, C2CEmit, C2CIntCodeUtils, C2CMain, C2CMode, C2COps, C2CRunTime, C2CNames, C2CStateUtils, C2CTarget, C2CTypes, IntCodeDefs, IntCodeUtils, IO, Rope; C2CVarImpl: CEDAR PROGRAM IMPORTS C2CAddressing, C2CAddressingOps, C2CBasics, C2CIntCodeUtils, C2CCodeUtils, C2CEmit, C2CMain, C2CMode, C2CNames, C2CRunTime, C2CStateUtils, C2COps, C2CTarget, C2CTypes, IntCodeUtils, IO, Rope EXPORTS C2CMain = BEGIN OPEN IntCodeDefs, C2CBasics, C2CDefs, C2CIntCodeUtils, C2CMain, C2CMode, C2CAddressing; ROPE: TYPE = Rope.ROPE; 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]] }; WordOffsetToAddressOffset: PROC [wo: Code] RETURNS [Code] = { RETURN [C2CEmit.BinOp[C2CCodeUtils.ConstI[C2CTarget.addressUnitsPerWord], " * ", wo, multiplicationPrecedence]] }; UnitPtrCast: PROC [sz: INT] RETURNS [cast: ROPE] = { SELECT TRUE FROM sz=C2CTarget.bitsPerWord => RETURN [C2CTarget.wordPtrCast]; sz=8 AND C2CTarget.hasBytes => RETURN [C2CTarget.bytePtrCast]; sz=C2CTarget.bitsPerHalfWord AND C2CTarget.hasHalfWords => RETURN [C2CTarget.halfWordPtrCast]; ENDCASE => CantHappen; }; CatVoided: PROC [cc, ccVoided: CodeCont] RETURNS [CodeCont] = { cc.sc ¬ Cat2[cc.sc, ccVoided.sc]; IF ccVoided.ec#NIL THEN cc.sc ¬ C2CEmit.Cat[cc.sc, "(void) ", ccVoided.ec, ";\n"]; RETURN [cc]; }; PlainIndexedField: PROC [sz, start: INT, bAddrC: Code, addrNotYetTaken: BOOL ¬ FALSE, base: Node] RETURNS [c: Code] = { IF sz#0 AND sz#C2CTarget.PointeeBits[sz] THEN CantHappen; IF addrNotYetTaken AND sz = C2CTarget.bitsPerWord AND (start MOD C2CTarget.bitsPerWord)=0 AND base.bits>0 AND (base.bits MOD C2CTarget.bitsPerWord)=0 AND base.bits<=C2CTarget.maxBitsForSimpleStructs AND start RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; HandleFieldLoc: PROC [varNode: Var, reqMode: Mode, fieldLoc: FieldLocation] RETURNS [cc: CodeCont] = { isLhs: BOOL ¬ LHSMode[reqMode]; baseSz: INT ¬ C2CMode.BaseSize[reqMode]; --not size of base but basicly used size! requestedAM: AddressMode ¬ GetAMode[reqMode]; baseMode: Mode ¬ NIL; --initialized only on need baseAM: AddressMode ¬ bad; --initialized only on need pseudoBaseSz: INT ¬ -1; --initialized only on need [assumed size of base] InitializeBaseMode: PROC[] = { IF baseMode=NIL THEN { IF baseSz=0 THEN baseMode ¬ C2CAddressing.ProposedMode[fieldLoc.base, isLhs, TRUE, 0] ELSE { pseudoBaseSz ¬ C2COps.MinContainerSize[fieldLoc.start, baseSz]; baseMode ¬ C2CAddressing.ProposedMode[fieldLoc.base, isLhs, TRUE, pseudoBaseSz]; }; baseMode ¬ DSetBaseSize[baseMode, baseSz]; baseAM ¬ GetAMode[baseMode]; }; }; GenericBaseForField: PROC [] RETURNS [bC: Code¬NIL] = { SELECT baseAM FROM plain, value, getAddr => { bcc: CodeCont ¬ GenNode[fieldLoc.base, baseMode]; cc.sc ¬ Cat2[cc.sc, bcc.sc]; IF bcc.ec#NIL THEN bC ¬ C2CEmit.MinPrecedence[bcc.ec, unaryPrecedence]; }; ENDCASE => CantHappen; }; AccessUnitAddr: PROC [baseC: Code, unitSize: INT, unitOff: INT, isAlreadyAddr: BOOL ¬ FALSE] RETURNS [code: Code] = { IF ~isAlreadyAddr THEN baseC ¬ C2CEmit.TakeAddr[baseC, TRUE]; code ¬ C2CEmit.CastRef[baseC, unitSize]; IF unitOff#0 THEN { code ¬ C2CEmit.Parentize[ C2CEmit.Cat[code, "+", C2CCodeUtils.ConstI[unitOff]] ]; code ¬ C2CEmit.SetRef[code, unitSize]; }; }; HandleComplexMask: PROC [] = { bcc: CodeCont; pointeeBaseBits: INT ¬ C2CTarget.PointeeBits[fieldLoc.base.bits]; IF fieldLoc.base.bits=0 OR varNode.bits+fieldLoc.start>fieldLoc.base.bits THEN CantHappen; bcc ¬ C2CAddressingOps.LoadArithNode[fieldLoc.base]; cc.sc ¬ Cat2[cc.sc, bcc.sc]; IF varNode.bits=1 AND BoolDontCareBit[] THEN { IF C2CTarget.maxBitsForFastLiterals>pointeeBaseBits-fieldLoc.start AND pointeeBaseBits=C2CTarget.bitsPerWord THEN { mask: ROPE ¬ C2CCodeUtils.ComplexMask[1, pointeeBaseBits-fieldLoc.start-1]; cc.ec ¬ C2CEmit.BinOp[bcc.ec, " & ", C2CEmit.IdentCode[mask], bitAndPrecedence]; RETURN }; }; cc.ec ¬ C2CCodeUtils.MaskNShift[bcc.ec, varNode.bits, pointeeBaseBits-fieldLoc.base.bits+fieldLoc.start, pointeeBaseBits]; RETURN; }; PlainFieldAsIndexing: PROC [] = { PeekCouldSimplyMask: PROC [] RETURNS [BOOL ¬ FALSE] = { IF varNode.bits=0 OR varNode.bits>C2CTarget.bitsPerWord THEN RETURN; -- test field IF fieldLoc.base.bits=0 OR fieldLoc.base.bits>C2CTarget.bitsPerWord THEN RETURN;-- test base IF varNode.bits+fieldLoc.start#fieldLoc.base.bits THEN RETURN; -- not exactly adjusted IF ~SizeIsProvableOk[fieldLoc.base] THEN RETURN; SELECT requestedAM FROM value, maskNShift, assUnits => {}; ENDCASE => RETURN [FALSE]; RETURN [TRUE]; }; PeekShouldMaskEvenIfComplex: PROC [] RETURNS [BOOL ¬ FALSE] = { IF varNode.bits=0 OR varNode.bits>C2CTarget.bitsPerWord THEN RETURN [FALSE]; -- test field IF fieldLoc.base.bits=0 OR fieldLoc.base.bits>C2CTarget.bitsPerWord THEN RETURN [FALSE]; -- test base IF ~SizeIsProvableOk[fieldLoc.base] THEN RETURN [FALSE]; SELECT requestedAM FROM value, maskNShift, assUnits => {}; ENDCASE => RETURN; WITH fieldLoc.base SELECT FROM var: Var => { IF var.flags[addressed] OR var.flags[upLevel] THEN RETURN [FALSE]; SELECT var.location.kind FROM localVar => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; ENDCASE => RETURN [FALSE]; }; addrNotYetTaken: BOOL ¬ FALSE; c: Code ¬ GenericBaseForField[]; SELECT baseAM FROM plain => { IF ~isLhs THEN {-- can't yet mask left hand size IF PeekCouldSimplyMask[] AND (SizeIsProvableOk[varNode] OR varNode.bits=baseSz) THEN { cc.ec ¬ C2CCodeUtils.MaskOut[c, varNode.bits]; RETURN }; IF PeekShouldMaskEvenIfComplex[] AND SizeIsProvableOk[varNode] THEN { HandleComplexMask; RETURN }; }; SELECT requestedAM FROM plain, value, assUnits, assBits => addrNotYetTaken ¬ TRUE; assAddr, getAddr, assBitAddr, getBitAddr => c ¬ C2CEmit.TakeAddr[c, TRUE]; ENDCASE => c ¬ C2CEmit.TakeAddr[c, TRUE]; }; getAddr => {}; assAddr => NotYetImpl; ENDCASE => CantHappen; cc.ec ¬ PlainIndexedField[IF baseSz=0 THEN 0 ELSE C2CTarget.PointeeBits[baseSz], fieldLoc.start, c, addrNotYetTaken, fieldLoc.base]; }; --PlainFieldAsIndexing GenericRHSForFieldLoc: PROC [] = { pointeeBits: INT ¬ C2CTarget.PointeeBits[varNode.bits]; InitializeBaseMode[]; IF baseAM=plain AND varNode.bits#0 AND C2COps.PlainAccess[fieldLoc.start, varNode.bits] THEN { PlainFieldAsIndexing[]; RETURN }; IF isLhs THEN CantHappen; IF baseAM=dummy THEN { cc.ec ¬ LoadDummy[varNode.bits]; RETURN }; IF baseAM#getAddr AND fieldLoc.base.bits<=C2CTarget.bitsPerWord AND SizeIsProvableOk[fieldLoc.base] THEN { HandleComplexMask[]; RETURN }; SELECT baseAM FROM plain, value, getAddr => { unitBits: INT ¬ pointeeBits; WHILE unitBits<=C2CTarget.bitsPerWord DO IF varNode.bits<=unitBits AND (fieldLoc.start MOD unitBits)+varNode.bits<=unitBits THEN { compensate: INT ¬ 0; unitOff: INT ¬ fieldLoc.start/unitBits; bitOffset: INT ¬ fieldLoc.start - unitOff*unitBits; isAlreadyAddr: BOOL ¬ FALSE; SELECT baseAM FROM plain, value => {}; getAddr => isAlreadyAddr ¬ TRUE; ENDCASE => NotYetImpl; IF fieldLoc.base.bitsunitBits-bitOffset THEN { mask: ROPE ¬ C2CCodeUtils.ComplexMask[1, unitBits-bitOffset-1]; cc.ec ¬ C2CEmit.BinOp[cc.ec, " & ", C2CEmit.IdentCode[mask], bitAndPrecedence]; RETURN }; }; BEGIN --Just try this little optimization; no side effect or complete RETURN TakingAddressIsFast: PROC [base: Node] RETURNS [BOOL ¬ FALSE] = { WITH base SELECT FROM var: Var => { IF var.flags[notRegister] OR var.flags[addressed] OR var.flags[upLevel] THEN RETURN [TRUE]; SELECT var.location.kind FROM deref, indexed => RETURN [TRUE]; ENDCASE => {} }; ENDCASE => {}; }; bigEndian: BOOL = TRUE; IF bigEndian AND bitOffset=0 AND compensate=0 AND baseAM=plain AND TakingAddressIsFast[fieldLoc.base] THEN { pTypeName: Rope.ROPE ¬ C2CTypes.DefinePtrType[unitBits]; rightSpares: INT ¬ unitBits-varNode.bits; cc.ec ¬ C2CEmit.TakeAddr[c: cc.ec, preventCastingToWord: TRUE]; cc.ec ¬ C2CEmit.PreventCastingToWord[cc.ec]; cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, unaryPrecedence]; cc.ec ¬ C2CEmit.Cat[" * (", pTypeName, ") ", cc.ec]; cc.ec ¬ C2CEmit.Cat[cc.ec, " >> ", C2CCodeUtils.RopeFromInt[rightSpares]]; cc.ec ¬ C2CEmit.Parentize[cc.ec]; RETURN }; END; cc.ec ¬ C2CCodeUtils.MaskNShift[cc.ec, varNode.bits, compensate+bitOffset, unitBits]; RETURN }; unitBits ¬ C2CTarget.PointeeBits[unitBits+1]; ENDLOOP; }; getBitAddr => {}; ENDCASE => {}; IF varNode.bits<=C2CTarget.bitsPerWord THEN { SELECT baseAM FROM value => CantHappen; --single word getAddr, plain => { ac: C2CAddressing.AddressContainer; cc1: CodeCont ¬ GenNode[fieldLoc.base, baseMode]; cc.sc ¬ Cat2[cc.sc, cc1.sc]; cc1.ec ¬ AccessUnitAddr[cc1.ec, C2CTarget.bitsPerWord, 0, baseAM=getAddr]; cc1.ec ¬ C2CEmit.CastWord[cc1.ec]; ac ¬ ACFromCodes[cc1.ec, C2CCodeUtils.ConstI[fieldLoc.start]]; cc.ec ¬ C2CEmit.Cat[C2CRunTime.ExtractField[ac, varNode.bits]]; }; getBitAddr => { ac: C2CAddressing.AddressContainer; cc1: CodeCont ¬ GenNode[fieldLoc.base, baseMode]; cc.sc ¬ Cat2[cc.sc, cc1.sc]; ac ¬ ACFromCodes[cc1.ec, AddConst[cc1.xbc, fieldLoc.start]]; cc.ec ¬ C2CEmit.Cat[C2CRunTime.ExtractField[ac, varNode.bits]]; }; ENDCASE => NotYetImpl; RETURN }; --IF NotYetImpl; cc.ec ¬ C2CEmit.Cat[cc.ec, "FunnyBitAddress"]; }; SELECT requestedAM FROM assAddr, plain, getAddr => { InitializeBaseMode[]; IF requestedAM=plain THEN { IF baseSz#0 AND ~C2COps.PlainAccess[fieldLoc.start, baseSz] THEN CantHappen; } ELSE { baseAM ¬ getAddr; baseMode ¬ DSetAMode[baseMode, baseAM]; }; SELECT baseAM FROM getAddr, plain => PlainFieldAsIndexing[]; ENDCASE => NotYetImpl; IF requestedAM#plain THEN cc ¬ C2CAddressingOps.ModizeArithCode[cc, reqMode, varNode.bits]; }; skip => { cc ¬ GenNode[fieldLoc.base, reqMode]; cc ¬ C2CAddressingOps.ModizeArithCode[cc, reqMode, varNode.bits]; }; assBitAddr => { off: Code ¬ IF fieldLoc.start=0 THEN NIL ELSE C2CCodeUtils.ConstI[fieldLoc.start]; cc ¬ MakeAssBitAdrAndOffset[fieldLoc.base, off, reqMode]; }; getBitAddr => { off: Code ¬ IF fieldLoc.start=0 THEN NIL ELSE C2CCodeUtils.ConstI[fieldLoc.start]; cc ¬ MakeGetBitAdrAndOffset[fieldLoc.base, off, reqMode]; }; assUnits => { GenericRHSForFieldLoc[]; cc ¬ C2CAddressingOps.ModizeArithCode[cc, reqMode, varNode.bits]; }; assBits => { GenericRHSForFieldLoc[]; cc ¬ C2CAddressingOps.ModizeArithCode[cc, reqMode, varNode.bits]; }; value, maskNShift => { InitializeBaseMode[]; SELECT baseAM FROM assBitAddr => { off: Code ¬ IF fieldLoc.start=0 THEN NIL ELSE C2CCodeUtils.ConstI[fieldLoc.start]; IF isLhs THEN ERROR NotYetImpl; IF varNode.bits>C2CTarget.bitsPerWord THEN NotYetImpl; IF requestedAM=value THEN { bitAddr: AddressContainer ¬ C2CStateUtils.ANewBitAddress[]; m: Mode ¬ SetAssBitAddr[NIL, bitAddr]; cc ¬ MakeAssBitAdrAndOffset[fieldLoc.base, off, m]; cc.ec ¬ C2CRunTime.ExtractField[bitAddr, varNode.bits]; } ELSE CantHappen; --I believe then requestedAM = assBitAddr }; getBitAddr => { off: Code ¬ IF fieldLoc.start=0 THEN NIL ELSE C2CCodeUtils.ConstI[fieldLoc.start]; IF isLhs THEN ERROR NotYetImpl; IF varNode.bits>C2CTarget.bitsPerWord THEN NotYetImpl; IF requestedAM=value THEN { cc ¬ MakeGetBitAdrAndOffset[fieldLoc.base, off, baseMode]; cc.ec ¬ C2CRunTime.ExtractField[ACFromCodes[cc.ec, cc.xbc], varNode.bits]; cc.xbc ¬ NIL; } ELSE CantHappen; --I believe then requestedAM = getBitAddr }; getAddr, plain, dummy => { GenericRHSForFieldLoc[]; }; value, maskNShift => { IF C2CTarget.PointeeBits[fieldLoc.base.bits] CantHappen; ENDCASE => CaseMissing; }; lHSMaskNShift => { VerySimpleVariable: PROC [node: IntCodeDefs.Node] RETURNS [BOOL] = { WITH node SELECT FROM var: IntCodeDefs.Var => { IF var.flags[notRegister] OR var.flags[addressed] THEN RETURN [FALSE]; WITH var.location SELECT FROM local: IntCodeDefs.LocalVarLocation => { IF var.bits<=C2CTarget.maxBitsForSimpleStructs THEN RETURN [TRUE]; }; ENDCASE; }; ENDCASE; RETURN [FALSE]; }; unitBits: INT ¬ C2CMode.UnitSize[reqMode]; unitOff: INT ¬ fieldLoc.start / unitBits; start: INT ¬ fieldLoc.start MOD unitBits; baseAMode: AddressMode; bCC: CodeCont; maskOut, maskIn, rhsC: Code; rhsTemplate: ROPE ¬ GetTemplate[reqMode]; --used just once; right adjusted zero fill rhsNode: IntCodeDefs.Node ¬ C2CMode.LHSMaskNShiftNode[reqMode]; --optionally rhsIsConst: BOOL; rhsConstVal: CARD; IF unitBits { IF ~SizeIsProvableOk[fieldLoc.base] OR fieldLoc.base.bits>C2CTarget.maxBitsForSimpleStructs OR ~VerySimpleVariable[fieldLoc.base] THEN { baseMode ¬ DSetAMode[baseMode, getAddr]; baseAMode ¬ getAddr }; }; getAddr => {}; assAddr => {}; ENDCASE => CantHappen; bCC ¬ GenNode[fieldLoc.base, baseMode]; cc.sc ¬ Cat2[cc.sc, bCC.sc]; cc.sc ¬ C2CEmit.CatDebugInfo[cc.sc, "field lhs"]; IF baseAMode=assAddr THEN { ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[baseMode]; baseMode ¬ DSetAMode[baseMode, getAddr]; baseAMode ¬ getAddr; IF bCC.ec#NIL THEN ERROR; bCC.ec ¬ C2CEmit.IdentCode[ac.words]; }; bCC.ec ¬ C2CEmit.MinPrecedence[bCC.ec, primaryPrecedence]; SELECT baseAMode FROM plain => { IF ~VerySimpleVariable[fieldLoc.base] THEN CantHappen; IF fieldLoc.base.bits>C2CTarget.bitsPerWord THEN { IF fieldLoc.base.bits > C2CTarget.maxBitsForSimpleStructs THEN CantHappen; bCC.ec ¬ C2CEmit.Cat[bCC.ec, IO.PutFR1[".f%g", IO.int[fieldLoc.start/C2CTarget.bitsPerWord]]]; }; unitBits ¬ fieldLoc.base.bits; IF unitBits>C2CTarget.bitsPerWord THEN unitBits ¬ C2CTarget.bitsPerWord; start ¬ fieldLoc.start MOD unitBits; }; getAddr => { useTemporary: BOOL ¬ FALSE; usedJustOnce: BOOL ¬ FALSE; IF rhsIsConst THEN { IF rhsConstVal=0 THEN usedJustOnce ¬ TRUE; IF rhsConstVal=BitMask[varNode.bits] THEN usedJustOnce ¬ TRUE; }; IF unitOff#0 THEN { bCC.ec ¬ C2CEmit.CastRef[bCC.ec, unitBits]; bCC.ec ¬ C2CEmit.Cat[bCC.ec, " + ", C2CCodeUtils.ConstC[unitOff]]; bCC.ec ¬ C2CEmit.Parentize[bCC.ec]; bCC.ec ¬ C2CEmit.SetRef[bCC.ec, unitBits]; bCC.ec ¬ C2CEmit.CatDebugInfo[bCC.ec, "field 0"]; useTemporary ¬ TRUE; }; IF ~usedJustOnce THEN { IF useTemporary OR C2CIntCodeUtils.UseTemporaryIfReused[fieldLoc.base, FALSE<>] THEN { temp: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "tadr"]; preCode: C2CEmit.Code ¬ C2CEmit.Cat[temp, " = ", C2CEmit.CastWord[bCC.ec], ";\n"]; preCode ¬ C2CEmit.CatDebugInfo[preCode, "field 1"]; cc.sc ¬ Cat2[cc.sc, preCode]; bCC.ec ¬ C2CEmit.IdentCode[temp]; }; }; bCC.ec ¬ C2CEmit.Deref[bCC.ec, unitBits]; }; ENDCASE => ERROR; IF (rhsIsConst AND rhsConstVal=0) OR Rope.Equal[rhsTemplate, "0"] THEN { mask: CARD ~ UMaskInverted[start, varNode.bits, unitBits]; cc.sc ¬ C2CEmit.Cat[cc.sc, bCC.ec, " &= ", C2CCodeUtils.ConstC[mask], ";\n"]; } ELSE IF rhsIsConst AND rhsConstVal=BitMask[varNode.bits] THEN { mask: CARD ~ UMask[start, varNode.bits, unitBits]; cc.sc ¬ C2CEmit.Cat[cc.sc, bCC.ec, " |= ", C2CCodeUtils.ConstC[mask], ";\n"]; } ELSE { bCC.ec ¬ C2CEmit.CatDebugInfo[bCC.ec, "field adr"]; maskOut ¬ C2CEmit.Cat[C2CEmit.CopyC[bCC.ec], " & ", C2CCodeUtils.ConstC[UMaskInverted[start, varNode.bits, unitBits]]]; maskOut ¬ C2CEmit.Parentize[maskOut]; IF rhsIsConst THEN { maskval: CARD ¬ rhsConstVal; IF unitBits#varNode.bits+start THEN { maskval ¬ LeftShift[maskval, unitBits-(varNode.bits+start)] }; maskIn ¬ C2CCodeUtils.ConstC[maskval]; } ELSE { maskIn _ C2CEmit.Parentize[C2CEmit.CastWord[rhsTemplate]]; IF unitBits#varNode.bits+start THEN { maskIn ¬ C2CEmit.Cat[maskIn, " << ", C2CCodeUtils.ConstI[unitBits-(varNode.bits+start)]]; maskIn ¬ C2CEmit.Parentize[maskIn]; }; }; rhsC ¬ C2CEmit.Cat[maskOut, " | ", maskIn]; cc.sc ¬ C2CEmit.Cat[cc.sc, bCC.ec, " = ", rhsC, ";\n"]; }; }; ENDCASE => CaseMissing; IF baseMode#NIL THEN FreeMode[baseMode]; }; --HandleFieldLoc UnitSizeForIndexMaskNShift: PROC [varBits: INT, base: Node] RETURNS [INT] = { pointeeBits: INT ¬ C2CTarget.PointeeBits[varBits]; IF pointeeBits>=C2CTarget.bitsPerWord THEN RETURN [pointeeBits]; WITH base SELECT FROM var: Var => WITH var.location SELECT FROM deref: DerefLocation => { IF deref.align>=C2CTarget.bitsPerWord THEN RETURN [C2CTarget.bitsPerWord]; IF deref.align=C2CTarget.bitsPerHalfWord AND C2CTarget.hasHalfWords AND pointeeBits<=C2CTarget.bitsPerHalfWord THEN RETURN [C2CTarget.bitsPerHalfWord]; RETURN [pointeeBits]; }; globalVar: GlobalVarLocation => RETURN [C2CTarget.bitsPerWord]; localVar: LocalVarLocation => RETURN [C2CTarget.bitsPerWord]; dummy: DummyLocation => RETURN [C2CTarget.bitsPerWord]; composite: CompositeLocation => IF base.bits>=C2CTarget.bitsPerWord THEN RETURN [C2CTarget.bitsPerWord]; field: FieldLocation => { IF field.start MOD C2CTarget.bitsPerWord = 0 THEN { x: INT ¬ UnitSizeForIndexMaskNShift[varBits, field.base]; IF base.bits>=x THEN RETURN [x]; }; RETURN [pointeeBits]; }; indexed: IndexedLocation => --should be optimized away-- RETURN [pointeeBits]; ENDCASE => RETURN [pointeeBits]; const: ConstNode => IF base.bits>=C2CTarget.bitsPerWord THEN RETURN [C2CTarget.bitsPerWord]; apply: ApplyNode => IF base.bits>=C2CTarget.bitsPerWord THEN RETURN [C2CTarget.bitsPerWord]; ENDCASE => {}; RETURN [pointeeBits]; }; HandleIndexedLoc: PROC [varNode: Var, mode: Mode, indexedLoc: IndexedLocation] RETURNS [cc: CodeCont] = { rqMode: Mode ¬ mode; rqAMode: C2CAddressing.AddressMode ¬ GetAMode[rqMode]; isLhs: BOOL ¬ LHSMode[rqMode]; baseSz: INT ¬ C2CMode.BaseSize[rqMode]; --not size of base but basicly used size! PlainIndexing: PROC [baseMode: Mode¬NIL] RETURNS [cc: CodeCont] = { pseudoBaseSz: INT ¬ IF baseSz=0 THEN 0 ELSE C2COps.MinContainerSize[varNode.bits, baseSz]; bm: Mode ¬ C2CAddressing.ProposedMode[indexedLoc.base, isLhs, TRUE, pseudoBaseSz]; baseAM: AddressMode ¬ GetAMode[bm]; IF varNode.bits=0 OR varNode.bits#C2CTarget.PointeeBits[varNode.bits] THEN CantHappen; bm ¬ SetBaseSize[bm, baseSz]; SELECT baseAM FROM plain, getAddr => { --therefore aligned basecc: CodeCont ¬ GenNode[indexedLoc.base, SetAMode[bm, getAddr]]; indexcc: CodeCont ¬ C2CAddressingOps.LoadArithNode[indexedLoc.index]; cc.sc ¬ Cat2[basecc.sc, indexcc.sc]; indexcc.ec ¬ C2CEmit.MinPrecedence[indexcc.ec, additionPrecedence]; basecc.ec ¬ C2CEmit.CastRef[basecc.ec, varNode.bits]; --make sure indexing is right cc.ec ¬ C2CEmit.Parentize[C2CEmit.Cat[basecc.ec, "+", indexcc.ec]]; cc.ec ¬ C2CEmit.SetRef[cc.ec, varNode.bits]; cc.ec ¬ C2CEmit.Deref[cc.ec, varNode.bits]; SELECT rqAMode FROM plain, value, maskNShift => { IF ~isLhs AND varNode.bits { m: Mode ¬ C2CMode.SetContainerSize[C2CMode.SetAMode[m: rqMode, am: assUnits], C2CTarget.bitsPerWord]; --template was already defined before cc.ec ¬ C2CEmit.TakeAddr[cc.ec, TRUE]; cc.sc ¬ C2CEmit.Cat[cc.sc, C2CAddressingOps.CodeToAssUnits[cc.ec, m]]; cc.ec ¬ NIL }; getAddr => cc.ec ¬ C2CEmit.TakeAddr[cc.ec, TRUE]; assUnits => { cc.sc ¬ C2CEmit.Cat[cc.sc, C2CAddressingOps.CodeToAssUnits[cc.ec, rqMode]]; cc.ec ¬ NIL; }; assBitAddr => {CantHappen; --delt with previously--}; ENDCASE => CaseMissing; RETURN; }; ENDCASE => {};--failed, go general case }; -- PlainIndexing IF varNode.bits=0 OR varNode.bits>C2CTarget.bitsPerWord AND (varNode.bits MOD C2CTarget.bitsPerWord # 0) THEN CantHappen; SELECT rqAMode FROM getAddr, plain, assAddr => { IF varNode.bits#C2CTarget.PointeeBits[varNode.bits] THEN CantHappen; cc ¬ PlainIndexing[]; IF cc.sc=NIL AND cc.ec=NIL THEN CantHappen; }; value, maskNShift => { OptimizeWithShiftNMask: PROC [] = { baseCC: CodeCont ¬ GenNode[indexedLoc.base, SetAMode[rqMode, getAddr]]; preCode, shift: Code ¬ NIL; unitSize: INT ¬ UnitSizeForIndexMaskNShift[varNode.bits, indexedLoc.base]; singleUnit: BOOL ¬ C2CIntCodeUtils.SizeIsProvableOk[indexedLoc.base] AND indexedLoc.base.bits<=unitSize; cc.sc ¬ Cat2[cc.sc, baseCC.sc]; baseCC.ec ¬ C2CEmit.MinPrecedence[baseCC.ec, unaryPrecedence]; indexcc.ec ¬ C2CEmit.MinPrecedence[indexcc.ec, additionPrecedence]; IF C2CIntCodeUtils.UseTemporaryIfReused[indexedLoc.index] THEN { temp: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "ix"]; preCode ¬ C2CEmit.Cat[temp, " = ", indexcc.ec, ",\n"]; indexcc.ec ¬ C2CEmit.IdentCode[temp]; }; baseCC.ec ¬ C2CEmit.CastRef[baseCC.ec, unitSize]; IF ~singleUnit THEN { divIndex: Code; divIndex ¬ C2CCodeUtils.ConstDiv[C2CEmit.CopyC[indexcc.ec], unitSize / varNode.bits]; divIndex ¬ C2CEmit.MinPrecedence[divIndex, multiplicationPrecedence]; baseCC.ec ¬ AddCodes[baseCC.ec, divIndex]; indexcc.ec ¬ C2CCodeUtils.ConstMod[indexcc.ec, unitSize / varNode.bits]; indexcc.ec ¬ C2CEmit.MinPrecedence[indexcc.ec, multiplicationPrecedence]; }; cc.ec ¬ C2CEmit.Deref[baseCC.ec, unitSize]; cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, additionPrecedence]; shift ¬ C2CCodeUtils.ConstMul[indexcc.ec, varNode.bits]; shift ¬ C2CEmit.MinPrecedence[shift, additionPrecedence]; shift ¬ C2CEmit.Cat[C2CCodeUtils.ConstI[unitSize-varNode.bits], " - (", shift, ")"]; cc.ec ¬ C2CEmit.Parentize[C2CEmit.Cat[cc.ec, " >> (", shift, ")"]]; cc.ec ¬ C2CCodeUtils.MaskOut[cc.ec, varNode.bits]; IF preCode#NIL THEN cc.ec ¬ C2CEmit.ParentizeAndLn[C2CEmit.Cat[preCode, cc.ec]]; }; OptimizeShiftNMaskVal: PROC [] = { baseSize: INT ¬ bSz; preCode, shift: Code ¬ NIL; baseCC: CodeCont ¬ C2CAddressingOps.LoadArithNode[indexedLoc.base]; baseCC.ec ¬ C2CEmit.MinPrecedence[baseCC.ec, additionPrecedence]; cc.sc ¬ Cat2[cc.sc, baseCC.sc]; IF ~SizeIsProvableOk[indexedLoc.base] THEN ERROR; --can't compute shift distance IF C2CIntCodeUtils.UseTemporaryIfReused[indexedLoc.index] THEN { temp: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "ix"]; preCode ¬ C2CEmit.Cat[temp, " = ", indexcc.ec, ",\n"]; indexcc.ec ¬ C2CEmit.IdentCode[temp]; }; shift ¬ C2CCodeUtils.ConstMul[indexcc.ec, varNode.bits];--left offset of leftmost bit wanted shift ¬ C2CEmit.MinPrecedence[shift, additionPrecedence]; shift ¬ C2CEmit.Cat[C2CCodeUtils.ConstI[baseSize-varNode.bits], " - ", shift];--shift amount baseCC.ec ¬ C2CEmit.CastWord[baseCC.ec]; cc.ec ¬ C2CEmit.Parentize[C2CEmit.Cat[baseCC.ec, " >> (", shift, ")"]]; cc.ec ¬ C2CCodeUtils.MaskOut[cc.ec, varNode.bits]; IF preCode#NIL THEN cc.ec ¬ C2CEmit.ParentizeAndLn[C2CEmit.Cat[preCode, cc.ec]]; }; indexcc: CodeCont; unitSize: INT ¬ C2CTarget.PointeeBits[varNode.bits]; bSz: INT ¬ MAX[baseSz, varNode.bits, indexedLoc.base.bits]; baseMode: Mode ¬ C2CAddressing.ProposedMode[indexedLoc.base, isLhs, TRUE, bSz]; baseAM: AddressMode ¬ GetAMode[baseMode]; baseMode ¬ SetBaseSize[baseMode, baseSz]; IF varNode.bits=unitSize THEN { cc ¬ PlainIndexing[]; IF cc.sc#NIL OR cc.ec#NIL THEN RETURN }; IF varNode.bits>C2CTarget.bitsPerWord THEN NotYetImpl; indexcc ¬ C2CAddressingOps.LoadArithNode[indexedLoc.index]; cc.sc ¬ Cat2[cc.sc, indexcc.sc]; IF (unitSize MOD varNode.bits = 0) AND ~LHSMode[rqMode] THEN { IF indexedLoc.base.bits<=C2CTarget.bitsPerWord AND SizeIsProvableOk[indexedLoc.base] THEN { OptimizeShiftNMaskVal[]; RETURN; }; IF baseAM=plain OR baseAM=assAddr OR baseAM=getAddr AND C2CTarget.maskNShiftLikeSun THEN { OptimizeWithShiftNMask[]; RETURN; }; }; SELECT baseAM FROM getAddr, assAddr, plain, getBitAddr, assBitAddr, maskNShift, value => { m: Mode ¬ SELECT baseAM FROM getAddr, assAddr, plain => SetAMode[rqMode, getAddr] ENDCASE => SetAMode[rqMode, getBitAddr]; baseCC: CodeCont ¬ GenNode[indexedLoc.base, m]; cc.sc ¬ Cat2[cc.sc, baseCC.sc]; baseCC.xbc ¬ AddCodes[baseCC.xbc, C2CCodeUtils.ConstMul[indexcc.ec, varNode.bits]]; cc.ec ¬ C2CRunTime.ExtractField[src: ACFromCodes[w: baseCC.ec, b: baseCC.xbc], bits: varNode.bits]; }; assBits, assUnits => CantHappen; ENDCASE => CaseMissing; }; assBitAddr => { cc1: CodeCont; indexcc: CodeCont ¬ C2CAddressingOps.LoadArithNode[indexedLoc.index]; cc.sc ¬ Cat2[cc.sc, indexcc.sc]; indexcc.ec ¬ C2CCodeUtils.ConstMul[indexcc.ec, varNode.bits]; cc1 ¬ MakeAssBitAdrAndOffset[indexedLoc.base, indexcc.ec, rqMode]; cc.sc ¬ Cat2[cc.sc, cc1.sc]; IF cc1.ec#NIL THEN CantHappen; }; getBitAddr => { cc1: CodeCont; indexcc: CodeCont ¬ C2CAddressingOps.LoadArithNode[indexedLoc.index]; cc.sc ¬ Cat2[cc.sc, indexcc.sc]; indexcc.ec ¬ C2CCodeUtils.ConstMul[indexcc.ec, varNode.bits]; cc1 ¬ MakeGetBitAdrAndOffset[indexedLoc.base, indexcc.ec, rqMode]; cc.sc ¬ Cat2[cc.sc, cc1.sc]; cc.ec ¬ cc1.ec; cc.xbc ¬ cc1.xbc; }; assUnits => { varcc: CodeCont ¬ GenVarNode[varNode, UseValue[varNode.bits, rqMode]]; cc.sc ¬ Cat2[cc.sc, varcc.sc]; cc.sc ¬ Cat2[cc.sc, C2CAddressingOps.CodeToAssUnits[varcc.ec, rqMode]]; }; assBits => { m1: Mode ¬ SetAMode[rqMode, getBitAddr]; addrCC: CodeCont ¬ GenVarNode[varNode, m1]; IF LHSMode[rqMode] THEN CantHappen; cc.sc ¬ C2CEmit.Cat[cc.sc, addrCC.sc, C2CRunTime.MoveField[ dst: GetAddrContainer[rqMode], src: ACFromCodes[w: addrCC.ec, b: addrCC.xbc], bits: ContainerSize[rqMode]], ";\n"]; }; skip => {--do it for side effects only IF ~IntCodeUtils.SideEffectFree[indexedLoc.base, FALSE] THEN { basecc: CodeCont ¬ GenNode[indexedLoc.base, rqMode]; cc ¬ CatVoided[cc, basecc]; }; IF ~IntCodeUtils.SideEffectFree[indexedLoc.index, FALSE] THEN { indexcc: CodeCont ¬ GenNode[indexedLoc.index, rqMode]; cc ¬ CatVoided[cc, indexcc]; }; }; lHSMaskNShift => { basePtrName, shiftName: ROPE ¬ NIL; preCode, maskOut, maskIn, rhsC, lhsC: Code ¬ NIL; indexCC, baseAddrCC: CodeCont; rhsTemplate: ROPE ¬ GetTemplate[rqMode]; --used just once; right adjusted zero fill unitSize: INT ¬ UnitSizeForIndexMaskNShift[varNode.bits, indexedLoc.base]; singleUnit: BOOL ¬ C2CIntCodeUtils.SizeIsProvableOk[indexedLoc.base] AND indexedLoc.base.bits<=unitSize; Shift: PROC [] RETURNS [shift: Code ¬ NIL] = { shift ¬ C2CCodeUtils.ConstMul[indexCC.ec, varNode.bits]; shift ¬ C2CEmit.MinPrecedence[shift, multiplicationPrecedence]; shift ¬ C2CEmit.Cat[shift, "+", C2CCodeUtils.ConstI[varNode.bits]]; shift ¬ C2CEmit.Cat[C2CCodeUtils.ConstI[unitSize], " - ", C2CEmit.Parentize[shift]]; shift ¬ C2CEmit.SetPrecedence[shift, additionPrecedence]; shift ¬ C2CEmit.CatDebugInfo[shift, "idx shift"]; }; IF varNode.bits>=C2CTarget.bitsPerWord THEN CantHappen; indexCC ¬ C2CAddressingOps.LoadArithNode[indexedLoc.index]; cc.sc ¬ Cat2[cc.sc, indexCC.sc]; indexCC.ec ¬ C2CEmit.MinPrecedence[indexCC.ec, additionPrecedence]; IF C2CIntCodeUtils.UseTemporaryIfReused[indexedLoc.index] THEN { shiftName ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "xs"]; cc.sc ¬ C2CEmit.Cat[cc.sc, shiftName, " = ", C2CEmit.CastWord[indexCC.ec], ";\n"]; indexCC.ec ¬ C2CEmit.IdentCode[shiftName]; }; baseAddrCC ¬ GenNode[indexedLoc.base, SetAMode[rqMode, getAddr]]; cc.sc ¬ Cat2[cc.sc, baseAddrCC.sc]; baseAddrCC.ec ¬ C2CEmit.MinPrecedence[baseAddrCC.ec, unaryPrecedence]; baseAddrCC.ec ¬ C2CEmit.CastRef[baseAddrCC.ec, unitSize]; IF ~singleUnit THEN { divIndex: Code ¬ C2CCodeUtils.ConstDiv[C2CEmit.CopyC[indexCC.ec], unitSize / varNode.bits]; divIndex ¬ C2CEmit.MinPrecedence[divIndex, multiplicationPrecedence]; indexCC.ec ¬ C2CCodeUtils.ConstMod[indexCC.ec, unitSize / varNode.bits]; indexCC.ec ¬ C2CEmit.MinPrecedence[indexCC.ec, multiplicationPrecedence]; baseAddrCC.ec ¬ C2CEmit.Parentize[AddCodes[baseAddrCC.ec, divIndex]]; baseAddrCC.ec ¬ C2CEmit.CatDebugInfo[baseAddrCC.ec, "idx baseAddrCC.ec"]; }; IF unitSize MOD varNode.bits = 0 THEN {--no unused bits to take care of... rhsNode: IntCodeDefs.Node ¬ C2CMode.LHSMaskNShiftNode[rqMode]; --optionally rhsIsConst: BOOL; rhsConstVal: CARD; [rhsIsConst, rhsConstVal] ¬ C2CIntCodeUtils.IsSimpleConst[rhsNode]; IF (rhsIsConst AND rhsConstVal=0) OR Rope.Equal[rhsTemplate, "0"] THEN { lhsC ¬ C2CEmit.Deref[baseAddrCC.ec, unitSize]; maskOut ¬ C2CEmit.Cat["(unsigned) ", C2CCodeUtils.Mask[varNode.bits], " << ", Shift[]]; cc.sc ¬ C2CEmit.Cat[cc.sc, lhsC, " &= ~(", maskOut, ");\n"]; RETURN }; IF rhsIsConst AND rhsConstVal=BitMask[varNode.bits] THEN { lhsC ¬ C2CEmit.Deref[baseAddrCC.ec, unitSize]; maskOut ¬ C2CEmit.Cat["(unsigned) ", C2CCodeUtils.Mask[varNode.bits], " << ", Shift[]]; cc.sc ¬ C2CEmit.Cat[cc.sc, lhsC, " |= (", maskOut, ");\n"]; RETURN }; }; basePtrName ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord]; cc.sc ¬ C2CEmit.Cat[cc.sc, basePtrName, " = ", C2CEmit.CastWord[baseAddrCC.ec], ";\n"]; baseAddrCC.ec ¬ C2CEmit.IdentCode[basePtrName]; lhsC ¬ C2CEmit.Deref[C2CEmit.CopyC[baseAddrCC.ec], unitSize]; rhsC ¬ C2CEmit.Deref[baseAddrCC.ec, unitSize]; rhsC ¬ C2CEmit.MinPrecedence[rhsC, unaryPrecedence]; IF shiftName=NIL THEN shiftName ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord, "sh"]; cc.sc ¬ C2CEmit.Cat[cc.sc, shiftName, " = ", Shift[], ";\n"]; maskOut ¬ C2CEmit.Cat["(unsigned) ", C2CCodeUtils.Mask[varNode.bits], " << ", shiftName]; maskOut ¬ C2CEmit.Parentize[C2CEmit.Cat[" ~ ", C2CEmit.Parentize[maskOut]]]; maskIn ¬ C2CEmit.Parentize[C2CEmit.Cat["(", rhsTemplate, ") << ", shiftName]]; rhsC ¬ C2CEmit.Cat["(", rhsC, " & ", maskOut, ")"]; rhsC ¬ C2CEmit.Cat[rhsC, " | ", maskIn]; cc.sc ¬ C2CEmit.Cat[cc.sc, lhsC, " = ", rhsC, ";\n"]; }; bad => CantHappen; ENDCASE => CaseMissing; }; BitMask: PROC [n: CARD] RETURNS [CARD] = { m: CARD ¬ 1; IF BITS[CARD]C2CTarget.bitsPerWord THEN CantHappen; --bad context IF n=BITS[CARD] THEN RETURN [LAST[CARD]]; WHILE n>0 DO n ¬ n-1; m ¬ m*2 ENDLOOP; RETURN [ m-1 ] }; LeftShift: PROC [c: CARD, by: CARD] RETURNS [CARD] = { WHILE by>0 DO c ¬ c*2; by ¬ by-1 ENDLOOP; RETURN [c]; }; UMask: PROC [start, bits, unitBits: INT] RETURNS [CARD] = { RETURN [LeftShift[BitMask[bits], unitBits-(start+bits)]]; }; UMaskInverted: PROC [start, bits, unitBits: INT] RETURNS [CARD] = { RETURN [UInvert[UMask[start, bits, unitBits], unitBits]]; }; Invert: PROC [c: CARD] RETURNS [CARD] = { IF BITS[CARD] RETURN [255-c]; 16 => RETURN [0FFFFH-c]; 32 => RETURN [0FFFFFFFFH-c]; ENDCASE => ERROR; }; MakeAssBitAdrAndOffset: PROC [base: Node, offEC: Code, mode: Mode] RETURNS [cc: CodeCont] = { baseSz: INT ¬ C2CMode.BaseSize[mode]; rqAMode: AddressMode ¬ GetAMode[mode]; baseMode: Mode ¬ C2CAddressing.ProposedMode[base, LHSMode[mode], TRUE, baseSz]; baseAM: AddressMode ¬ GetAMode[baseMode]; mode2: Mode; basecc: CodeCont; ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[mode]; IF rqAMode#assBitAddr THEN CantHappen; IF offEC#NIL THEN offEC ¬ C2CEmit.MinPrecedence[offEC, unaryPrecedence]; SELECT baseAM FROM plain => { baseMode ¬ DSetBaseSize[baseMode, 0]; basecc ¬ GenNode[base, baseMode]; cc.sc ¬ Cat2[cc.sc, basecc.sc]; basecc.ec ¬ C2CEmit.TakeAddr[basecc.ec]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.words, " = ", basecc.ec, ";\n"]; IF offEC=NIL THEN offEC ¬ C2CCodeUtils.ConstI[0]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = ", offEC, ";\n"]; }; getAddr => { baseMode ¬ DSetBaseSize[baseMode, 0]; basecc ¬ GenNode[base, baseMode]; cc.sc ¬ Cat2[cc.sc, basecc.sc]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.words, " = ", C2CEmit.CastWord[basecc.ec], ";\n"]; IF offEC=NIL THEN offEC ¬ C2CCodeUtils.ConstI[0]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = ", offEC, ";\n"]; }; value => { baseMode ¬ DSetBaseSize[baseMode, baseSz]; basecc ¬ GenNode[base, baseMode]; IF basecc.ec=NIL THEN CantHappen; cc.sc ¬ Cat2[cc.sc, basecc.sc]; IF C2CEmit.GetAddressable[basecc.ec] THEN basecc.ec ¬ C2CEmit.TakeAddr[basecc.ec, TRUE] ELSE { sz: INT ¬ C2CTarget.TemporaryBits[base.bits]; template: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, sz]; IF LHSMode[mode] THEN CantHappen; cc.sc ¬ C2CEmit.Cat[cc.sc, template, " = ", basecc.ec, ";\n"]; basecc.ec ¬ C2CEmit.Cat["&", template]; IF base.bits { mode2 ¬ SetAssBitAddr[mode, ac]; mode2 ¬ DSetBaseSize[mode2, baseSz]; basecc ¬ GenNode[base, mode2]; IF basecc.ec#NIL THEN CantHappen; cc.sc ¬ Cat2[cc.sc, basecc.sc]; IF offEC#NIL THEN cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " += ", offEC, ";\n"]; }; getBitAddr, lHSMaskNShift => { baseMode ¬ DSetAMode[baseMode, getBitAddr]; baseMode ¬ DSetBaseSize[baseMode, baseSz]; basecc ¬ GenNode[base, baseMode]; cc.sc ¬ Cat2[cc.sc, basecc.sc]; IF basecc.ec=NIL THEN CantHappen; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.words, " = ", C2CEmit.CastWord[basecc.ec], ";\n"]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = ", AddCodes[basecc.xbc, offEC], ";\n"]; }; ENDCASE => CaseMissing; IF cc.ec#NIL THEN CantHappen; }; --MakeAssBitAdrAndOffset MakeGetBitAdrAndOffset: PROC [base: Node, offEC: Code, mode: Mode] RETURNS [cc: CodeCont] = { baseSz: INT ¬ BaseSize[mode]; rqAMode: AddressMode ¬ GetAMode[mode]; baseMode: Mode ¬ C2CAddressing.ProposedMode[base, LHSMode[mode], TRUE, baseSz]; baseAM: AddressMode ¬ GetAMode[baseMode]; IF rqAMode#getBitAddr THEN CantHappen; IF offEC#NIL THEN offEC ¬ C2CEmit.MinPrecedence[offEC, unaryPrecedence]; SELECT baseAM FROM plain => { baseMode ¬ SetBaseSize[baseMode, 0]; cc ¬ GenNode[base, baseMode]; cc.ec ¬ C2CEmit.TakeAddr[cc.ec, TRUE]; cc.xbc ¬ offEC; }; getAddr => { baseMode ¬ SetBaseSize[baseMode, 0]; cc ¬ GenNode[base, baseMode]; cc.ec ¬ C2CEmit.CastWord[cc.ec]; cc.xbc ¬ offEC; }; value, maskNShift => { baseMode ¬ SetBaseSize[baseMode, baseSz]; cc ¬ GenNode[base, baseMode]; IF C2CEmit.GetAddressable[cc.ec] THEN cc.ec ¬ C2CEmit.TakeAddr[cc.ec, TRUE] ELSE { sz: INT ¬ C2CTarget.TemporaryBits[base.bits]; template: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, sz]; IF LHSMode[mode] THEN CantHappen; cc.sc ¬ C2CEmit.Cat[cc.sc, template, " = ", cc.ec, ";\n"]; cc.ec ¬ C2CEmit.Cat["&", template]; IF base.bits { NotYetImpl; }; getBitAddr, lHSMaskNShift => { baseMode ¬ SetBaseSize[baseMode, 0]; baseMode ¬ DSetAMode[baseMode, getBitAddr]; cc ¬ GenNode[base, baseMode]; cc.xbc ¬ AddCodes[cc.xbc, offEC, TRUE]; }; ENDCASE => CaseMissing; IF cc.ec=NIL THEN CantHappen; }; --MakeGetBitAdrAndOffset AddCodes: PROC [c1, c2: Code ¬ NIL, returnNil: BOOL ¬ FALSE] RETURNS [Code] = { SELECT TRUE FROM c1 = NIL AND c2 = NIL => IF returnNil THEN RETURN [NIL] ELSE RETURN [C2CCodeUtils.ConstI[0]]; c1 = NIL => RETURN [c2]; c2 = NIL => RETURN [c1]; ENDCASE => RETURN [C2CEmit.BinOp[c1, " + ", c2, additionPrecedence]]; }; AddConst: PROC [c: Code, const: INT] RETURNS [c1: Code] = { c1 ¬ IF const = 0 THEN NIL ELSE C2CCodeUtils.ConstI[const]; c1 ¬ AddCodes[c, c1, FALSE]; }; HandleDerefLoc: PROC [varNode: Var, mode: Mode, derefLoc: DerefLocation] RETURNS [cc: CodeCont] = { Aligned: PROC [] RETURNS [BOOL ¬ TRUE] = { IF derefLoc.align {cc.ec ¬ addrcc.ec}; assBits => { dst: C2CAddressing.AddressContainer ¬ GetAddrContainer[rqMode]; cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.MoveField[ dst: dst, src: ACFromCodes[C2CEmit.CastWord[addrcc.ec], NIL], bits: ContainerSize[rqMode] ], ";\n" ]; cc.ec ¬ NIL; }; assUnits => { pBits: INT ¬ IF baseSz=0 THEN 0 ELSE C2CTarget.PointeeBits[baseSz]; IF baseSz=0 THEN NotYetImpl; IF baseSz#varNode.bits THEN NotYetImpl; IF Aligned[] THEN { cc.ec ¬ C2CEmit.Deref[addrcc.ec, pBits]; cc.sc ¬ C2CEmit.Cat[cc.sc, C2CAddressingOps.CodeToAssUnits[cc.ec, rqMode]]; cc.ec ¬ NIL; } ELSE { rqSz: INT ¬ varNode.bits; tSz: INT ¬ ContainerSize[rqMode]; boff: ROPE ¬ C2CCodeUtils.RopeFromInt[tSz-rqSz]; IF tSzrqSz THEN { cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.DepositField[ dst: [GetTemplate[mode], " 0"], bits: tSz-rqSz, word: C2CCodeUtils.ConstI[0] ], ";\n" ]; }; cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.MoveField[ dst: [GetTemplate[mode], boff], src: ACFromCodes[C2CEmit.CastWord[addrcc.ec], NIL], bits: rqSz ], ";\n" ]; cc.ec ¬ NIL; }; }; assAddr => { template: ROPE ¬ GetTemplate[mode]; cc.sc ¬ C2CEmit.Cat[cc.sc, template, " = ", C2CEmit.CastWord[addrcc.ec], ";\n"]; }; assBitAddr => { ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[mode]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.words, " = ", C2CEmit.CastWord[addrcc.ec], "; "]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = 0;\n"]; IF ac.words=NIL OR ac.bits=NIL THEN CantHappen; }; plain => { pBits: INT ¬ IF baseSz=0 THEN 0 ELSE C2CTarget.PointeeBits[baseSz]; cc.ec ¬ C2CEmit.Deref[addrcc.ec, pBits]; }; maskNShift => { pBits: INT ¬ C2CTarget.PointeeBits[baseSz]; IF LHSMode[rqMode] THEN NotYetImpl; IF varNode.bits=0 THEN NotYetImpl; IF pBits>C2CTarget.bitsPerWord THEN NotYetImpl; cc.ec ¬ C2CEmit.Deref[addrcc.ec, pBits]; }; value => { pBits: INT ¬ IF baseSz=0 THEN 0 ELSE C2CTarget.PointeeBits[baseSz]; IF LHSMode[rqMode] THEN NotYetImpl; IF varNode.bits=0 OR baseSz=0 THEN NotYetImpl; IF Aligned[] THEN { cc.ec ¬ C2CEmit.Deref[addrcc.ec, pBits]; } ELSE { ac: C2CAddressing.AddressContainer ¬ ACFromCodes[C2CEmit.CastWord[addrcc.ec], NIL]; IF varNode.bits#baseSz THEN NotYetImpl; IF varNode.bits<=C2CTarget.bitsPerWord THEN cc.ec ¬ C2CRunTime.ExtractField[src: ac, bits: varNode.bits] ELSE { template: ROPE ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.TemporaryBits[varNode.bits]]; cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.MoveField[src: ac, dst: [Rope.Concat["&", template], "0"], bits: varNode.bits ], ";\n" ]; cc.ec ¬ C2CEmit.IdentCode[template]; }; }; }; skip => {--done for side effects only cc ¬ CatVoided[cc, addrcc]; }; ENDCASE => CaseMissing; }; HandleCompositeLoc: PUBLIC PROC [varNode: Var, mode: Mode, compositeLoc: CompositeLocation, hackAddr: ROPE ¬ NIL] RETURNS [cc: CodeCont] = { temporary: ROPE ¬ NIL; temporaryAddr: ROPE ¬ hackAddr; isFirst: BOOL ¬ TRUE; specialCaseAlreadyModized: BOOL ¬ FALSE; bitsSofar: INT ¬ 0; reqAMode: AddressMode ¬ GetAMode[mode]; IF hackAddr#NIL THEN { IF varNode.bits<=C2CTarget.bitsPerWord THEN CantHappen; IF reqAMode#skip THEN CantHappen; }; IF ~ExpMode[mode] THEN CantHappen; IF LHSMode[mode] THEN NotYetImpl; IF reqAMode=assUnits AND varNode.bits>C2CTarget.bitsPerWord THEN { specialCaseAlreadyModized ¬ TRUE; temporary ¬ GetTemplate[mode]; }; IF varNode.bits>C2CTarget.bitsPerWord THEN { AllocSourceBA: PROC [] RETURNS [AddressContainer] = { IF srcBA.words=NIL THEN srcBA ¬ C2CStateUtils.ANewBitAddress[]; RETURN [srcBA] }; destBA, srcBA: AddressContainer ¬ [NIL, NIL]; IF hackAddr=NIL THEN { temporary ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.TemporaryBits[varNode.bits], "temp"]; temporaryAddr ¬ Rope.Concat["&", temporary]; }; destBA.words ¬ temporaryAddr; FOR list: NodeList ¬ compositeLoc.parts, list.rest WHILE list#NIL DO piece: Node ¬ list.first; OddPiece: PROC [] = { destBA.bits ¬ C2CCodeUtils.RopeFromInt[bitsSofar]; IF piece.bits<=C2CTarget.bitsPerWord THEN { piececc: CodeCont ¬ C2CAddressingOps.LoadArithNode[piece]; cc.sc ¬ Cat2[cc.sc, piececc.sc]; piececc.ec ¬ C2CEmit.MinPrecedence[piececc.ec, assignPrecedence]; cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.DepositField[dst: destBA, bits: piece.bits, word: piececc.ec], ";\n" ]; } ELSE { mode: Mode ¬ SetAssBitAddr[UseValue[piece.bits], AllocSourceBA[]]; piececc: CodeCont ¬ GenNode[piece, mode]; cc.sc ¬ Cat2[cc.sc, piececc.sc]; IF piececc.ec#NIL THEN CantHappen; cc.sc ¬ C2CEmit.Cat[cc.sc, "(void) ", C2CRunTime.MoveField[dst: destBA, src: srcBA, bits: piece.bits], ";\n" ]; }; }; WellAlligned: PROC [] RETURNS [BOOL] = { IF piece.bits#C2CTarget.PointeeBits[piece.bits] THEN RETURN [FALSE]; IF (bitsSofar MOD C2CTarget.bestAlignment)=0 THEN RETURN [TRUE]; IF (bitsSofar MOD C2CTarget.bitsPerWord)=0 THEN RETURN [piece.bits<=C2CTarget.bitsPerWord]; IF (bitsSofar MOD C2CTarget.bitsPerHalfWord)=0 AND C2CTarget.hasHalfWords THEN RETURN [piece.bits<=C2CTarget.bitsPerHalfWord]; IF (bitsSofar MOD 8) = 0 AND C2CTarget.hasBytes THEN RETURN [piece.bits<=8]; RETURN [FALSE]; }; piececc: CodeCont; pieceMode: Mode ¬ C2CAddressing.ProposedMode[piece, FALSE, FALSE, piece.bits]; pieceAMode: AddressMode ¬ GetAMode[pieceMode]; pieceMode ¬ UseValue[piece.bits, pieceMode]; IF piece.bits=0 THEN NotYetImpl; IF ~WellAlligned[] THEN OddPiece[] ELSE { SELECT pieceAMode FROM plain, value, maskNShift, dummy => { unit: INT ¬ MIN[C2CTarget.bitsPerWord, piece.bits]; unitPtr: Code ¬ C2CEmit.CastRef[C2CEmit.IdentCode[temporaryAddr], unit]; IF bitsSofar#0 THEN { unitPtr ¬ AddConst[unitPtr, bitsSofar/unit]; unitPtr ¬ C2CEmit.SetRef[unitPtr, unit]; }; piececc ¬ GenNode[piece, pieceMode]; cc.sc ¬ Cat2[cc.sc, piececc.sc]; piececc.ec ¬ C2CEmit.MinPrecedence[piececc.ec, unaryPrecedence]; IF unit OddPiece[]; }; bitsSofar ¬ bitsSofar+piece.bits; ENDLOOP; SELECT reqAMode FROM skip => {}; ENDCASE => {cc.ec ¬ C2CEmit.IdentCode[temporary]}; --modized outside of IF } ELSE { FOR list: NodeList ¬ compositeLoc.parts, list.rest WHILE list#NIL DO piece: Node ¬ list.first; piececc: CodeCont; bitsSofar ¬ bitsSofar+piece.bits; IF isFirst THEN { is: BOOL; value: CARD; [is, value] ¬ C2CIntCodeUtils.IsSimpleConst[piece]; IF is AND value=0 THEN LOOP; }; piececc ¬ C2CAddressingOps.LoadArithNode[piece]; cc.sc ¬ Cat2[cc.sc, piececc.sc]; piececc.ec ¬ C2CEmit.CastWord[piececc.ec]; IF isFirst THEN {isFirst ¬ FALSE; cc.ec ¬ piececc.ec} ELSE { cc.ec ¬ C2CEmit.Cat["(", C2CEmit.CastWord[cc.ec], " << ", C2CCodeUtils.ConstI[piece.bits], ")"]; cc.ec ¬ C2CEmit.Cat[cc.ec, " + ", piececc.ec]; cc.ec ¬ C2CEmit.Parentize[cc.ec]; }; ENDLOOP; IF isFirst THEN cc.ec ¬ C2CCodeUtils.ConstI[0]; --all the parts were constant and 0 }; IF bitsSofar#varNode.bits THEN CantHappen; IF specialCaseAlreadyModized THEN cc.ec ¬ NIL ELSE cc ¬ C2CAddressingOps.ModizeArithCode[cc, mode, varNode.bits] }; DummyDataRec: TYPE = RECORD[name: ROPE, bits: INT]; MakeOrFindRHSDummy: PUBLIC PROC [bits: INT] RETURNS [name: ROPE] = { WITH C2CBasics.GetProp[$dummyDataRec] SELECT FROM ddrp: REF DummyDataRec => { IF ddrp.bits>=bits THEN RETURN [ddrp.name]; }; ENDCASE => {}; WITH C2CBasics.GetProp[$LargestDummy] SELECT FROM ri: REF INT => bits ¬ MAX[bits, ri­]; ENDCASE => {}; bits ¬ C2CTarget.RoundUpToWordBoundary[bits]; name ¬ C2CStateUtils.DeclareVariable[moduleDeclarations, bits, "dummy"]; C2CEmit.AppendCode[moduleInitializations, C2CEmit.Cat[ C2CRunTime.FillWords[dst: C2CEmit.Cat["&", name], times: C2CTarget.BitsToWords[bits], value: C2CCodeUtils.ConstI[0]], ";\n" ] ]; C2CBasics.PutProp[$dummyDataRec, NEW[DummyDataRec ¬ [name, bits]]]; }; LoadDummy: PROC [bits: INT] RETURNS [c: Code] = { IF bits<=C2CTarget.bitsPerWord THEN c ¬ C2CEmit.IdentCode["0"] ELSE { c ¬ C2CEmit.IdentCode[MakeOrFindRHSDummy[bits]]; c ¬ C2CEmit.TakeAddr[c, TRUE]; c ¬ C2CEmit.CastRef[c, bits]; c ¬ C2CEmit.Deref[c, bits]; }; }; HandleDummyLoc: PROC [varNode: Var, mode: Mode] RETURNS [cc: CodeCont] = { IF LHSMode[mode] THEN { IF GetAMode[mode]#dummy THEN NotYetImpl; RETURN; --don't generate anything }; cc.ec ¬ LoadDummy[varNode.bits]; IF GetAMode[mode]#dummy THEN cc ¬ C2CAddressingOps.ModizeArithCode[cc, mode, varNode.bits]; }; GenVarNode: PUBLIC PROC [varNode: Var, mode: Mode] RETURNS [cc: CodeCont] = { HandleVanillaLoc: PROC [base: ROPE, mode: Mode, isRegister: BOOL ¬ FALSE] RETURNS [cc: CodeCont] = { SELECT GetAMode[mode] FROM assBitAddr => { ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[mode]; cc.sc ¬ C2CEmit.Cat[ac.words, " = (word) &", base, "; "]; cc.sc ¬ C2CEmit.Cat[cc.sc, ac.bits, " = 0;\n"]; IF ac.words=NIL OR ac.bits=NIL THEN CantHappen; IF isRegister THEN NotYetImpl; }; assAddr => { template: ROPE ¬ GetTemplate[mode]; cc.sc ¬ C2CEmit.Cat[template, " = (word) &", base, ";\n"]; IF isRegister THEN NotYetImpl; }; assUnits => { IF varNode.bits#C2CTarget.PointeeBits[varNode.bits] THEN NotYetImpl; cc.sc ¬ C2CAddressingOps.CodeToAssUnits[C2CEmit.IdentCode[base], mode]; }; assBits => { ac: C2CAddressing.AddressContainer ¬ GetAddrContainer[mode]; bits: INT ¬ ContainerSize[mode]; IF bits=0 THEN CantHappen; IF varNode.bits#C2CTarget.TemporaryBits[varNode.bits] THEN NotYetImpl; IF bits#varNode.bits THEN NotYetImpl; IF bits <= C2CTarget.bitsPerWord THEN { cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.DepositField[dst: ac, bits: bits, word: C2CEmit.IdentCode[base]], ";\n" ]; } ELSE { cc.sc ¬ C2CEmit.Cat[cc.sc, C2CRunTime.MoveField[dst: ac, bits: bits, src: ACFromCodes[C2CEmit.TakeAddr[C2CEmit.IdentCode[base], TRUE], NIL] ], ";\n" ]; }; }; getAddr, getBitAddr => { cc.ec ¬ C2CEmit.TakeAddr[C2CEmit.IdentCode[base], TRUE]; IF isRegister THEN NotYetImpl; }; plain => { cc.ec ¬ C2CEmit.IdentCode[base]; IF varNode.bits#C2CTarget.TemporaryBits[varNode.bits] THEN NotYetImpl; IF isRegister THEN cc.ec ¬ C2CEmit.SetAddressable[cc.ec, FALSE]; }; value, maskNShift => { cc.ec ¬ C2CEmit.IdentCode[base]; IF isRegister THEN cc.ec ¬ C2CEmit.SetAddressable[cc.ec, FALSE]; IF varNode.bits#C2CTarget.TemporaryBits[varNode.bits] THEN { IF varNode.bits>C2CTarget.bitsPerWord THEN NotYetImpl; cc.ec ¬ C2CCodeUtils.MaskNShift[cc.ec, varNode.bits, 0, C2CTarget.TemporaryBits[varNode.bits]]; }; }; skip => {--no side effects--}; ENDCASE => CaseMissing; }; GetName: PROC [] RETURNS [name: ROPE] = { IF varNode.id=nullVariableId THEN CantHappen; name ¬ C2CNames.VarName[id: varNode.id, class: "var"]; }; EmitNameAsComment: PROC [] = { IF varNode.id#nullVariableId THEN { name: ROPE ¬ C2CNames.VarName[id: varNode.id, class: "var"]; IF cc.ec#NIL THEN cc.ec ¬ C2CEmit.CatRemark[cc.ec, name] ELSE IF cc.sc#NIL THEN cc.sc ¬ C2CEmit.CatRemark[cc.sc, name] ELSE cc.sc ¬ C2CEmit.Cat[C2CEmit.CatRemark[cc.sc, Rope.Concat["node removed: ", name]], C2CEmit.line]; }; }; CheckGlobalAccess: PROC [id: LogicalId] = { WITH C2CBasics.GetProp[$IdsInGlobalFrame] SELECT FROM tab: IntCodeUtils.IdTab => IF IntCodeUtils.Fetch[tab, id]=$UseGlobalFrame THEN CantHappen; ENDCASE => {}; }; mode ¬ SetExpr[mode]; IF varNode.location=nullLocation THEN CantHappen; WITH varNode.location SELECT FROM globLoc: GlobalVarLocation => { CheckGlobalAccess[globLoc.id]; cc ¬ HandleVanillaLoc[GetName[], mode]; }; locLoc: LocalVarLocation => { cc ¬ HandleVanillaLoc[GetName[], mode, varNode.bits=32 AND varNode.flags[frequent]]; }; derefLoc: DerefLocation => { cc ¬ HandleDerefLoc[varNode: varNode, mode: mode, derefLoc: derefLoc]; EmitNameAsComment[]; }; indexedLoc: IndexedLocation => { cc ¬ HandleIndexedLoc[varNode: varNode, mode: mode, indexedLoc: indexedLoc]; EmitNameAsComment[]; }; fieldLoc: FieldLocation => { cc ¬ HandleFieldLoc[varNode: varNode, reqMode: mode, fieldLoc: fieldLoc]; EmitNameAsComment[]; }; compositeLoc: CompositeLocation => { cc ¬ HandleCompositeLoc[varNode: varNode, mode: mode, compositeLoc: compositeLoc]; }; dummyLoc: DummyLocation => { cc ¬ HandleDummyLoc[varNode: varNode, mode: mode]; }; stackLoc: StackLocation => CantHappen; upLevelLoc: UpLevelLocation => CantHappen; escLoc: EscapeLocation => CantHappen; sysLoc: SystemLocation => CantHappen; ENDCASE => CaseMissing; FreeMode[mode]; }; END. Ξ C2CVarImpl.mesa Copyright Σ 1987, 1988, 1989, 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Christian Jacobi, 1987 Christian Jacobi, May 4, 1993 8:45 pm PDT Willie-s, September 24, 1991 6:08 pm PDT CURRENTLY DEFINED FOR FIELD, NOT INDEXED --if bAddrC is address [except if addrNotYetTaken], accesses field with size sz at position start --assumes all alignment requirements ok we try not to use address; this allows the C compiler to put the base into a register --make sure size is ok ! --makes sure baseMode, baseAM, and, pseudoBaseSz are defined --caller needs outside knowlede whether addr or base is loaded --The case where we want the shift and mask instructions to handle field access (rhs) --Requirement 1: fieldLoc.base.bits<=C2CTarget.bitsPerWord --Requirement 2: SizeIsProvableOk[fieldLoc.base] --the nice and easy case of field access --recognizes case where field is exactly right adjusted in word --Case introduced to avoid taking address of local variables which would force local variable into memory --PlainFieldAsIndexing --Caveat: Valid only in cases where varNode.bits is well defined --will not yet call C2CAddressingOps.ModizeArithCode --taking this case first prevents us from taking the addr of an expression which is not lvalue or, which we might prefer to remain stored in a register --baseAM: so the alignment will be ok --access field completely in one unit endian !!! --Masking out part of word if left boundary of part starts at unit boundary --Use deref and shift instead of two shifts... --access field crossing wordboundary --HandleFieldLoc --alignment ok! --This might be somewhat inefficient --This might be somewhat inefficient --but requestedAM#assBitAddr --but requestedAM#assBitAddr --??note: varNode.bits are defined, since rqAm in [maskNShift, value] --note: varNode.bits are defined, since rqAm in [maskNShift, value] --Recognizes simple local variables which might be put into registers It might be appropriate to add a test for the alignment template is always in range ! Not necessary maskIn _ C2CEmit.Cat[C2CCodeUtils.Mask[varNode.bits], " & ", rhsTemplate]; --pointeebits is always safe, but sometimes not efficient --pointeebits works, otherwise it would not require maskNShift mode --don't consider varBits=bitsPerByte, bitsPerHalfWord; we are maskNShift'ing anyway --Either handles the case completely or returns cc empty and makes no costly side effects --offset --HandleIndexedLoc --base is right adjusted! --simply retry with different mode --simply retry with different mode --compute code for shift, using indexCC.ec-- Creates a mask with n (rightmost) bits set to one Creates a mask with specified "bits" bits set to one Positioned at start bits from the LEFT on unitBits large unit Creates a mask with non specified "bits" bits set to one Positioned at start bits from the LEFT on unitBits large unit --Reqired: mode=assBitAddr --offEC: bit offset; NIL for 0 YYY should test whether base.bits is valid --value was right adjusted --Reqired: mode=getBitAddr --offEC: bit offset; NIL for 0 YYY we should test whether base.bits is valid --value was right adjusted -- allows NIL code input for 0 -- IF returnNil allows NIL code output for 0 -- allows NIL code as 0 --left justified --should look similar to assBits, except right justified fill left spare of destination template with 0 --move value to right of template --don't AlignmentTest: requestor responsible --don't AlignmentTest: requestor responsible --hackAddr: efficiency hack; -- if present composite location is generated into *hackAddr -- required mode must be skip -- hackAddr may be evaluated multiple times --needs multi words --piece fits in word --piece does not fit in word --Don't cast to word; all we do is an assignment --fits into single word --Generates code code to return 0 expression --only useage of var; no declaration ! --Returns base or a bit-address for base --Assumes base at least identPrecedence --XXX Is this vanilla loc right or left adjusted? I don't care since bits must match --take the leftmost bits -- globals: varNode -- globals: varNode, cc --C2C assumed the front end would compute all accesses of this variable --using pointers to the global frame. --we are NOT! in declaration mode --ignore locLoc.parent Κ5b–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ ΟeœU™`Kšœ™K™)K™(K™—šΟk ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšžœ˜Kšœ˜K˜—šΟn œžœž˜KšžœΏ˜ΖKšžœ ˜—šž˜KšžœS˜WK˜—Kšžœžœžœ˜K˜šŸœžœžœ˜/Kšžœžœžœžœ˜Kšžœžœžœžœ˜Kšžœ˜Kšœ˜—K˜šŸœžœ žœ ˜=Kšžœi˜oK˜—K™š Ÿ œžœžœžœžœ˜4šžœžœž˜Kšœžœ˜;Kšœžœžœ˜>Kšœžœžœ˜^Kšžœ˜—K˜—K˜šŸ œžœžœ˜?Kšœ!˜!Kšžœ žœžœ;˜RKšžœ˜ K˜—K™K™šŸ(™(K™—š Ÿœžœ žœ!žœžœžœ˜wKšΟca™aKš '™'Kšžœžœžœ ˜9šžœžœžœžœžœ žœ žœžœ.žœ)žœžœ˜”KšœU™Ušžœ žœ˜(Kš ™Kšœ0žœ˜BKšœ˜—Kšœ5˜5Kš žœ žœ! œžœžœ˜OKšœžœžœ$˜KKšœ0˜0Kšž˜Kšœ˜—šžœžœ˜Kšœ"žœ˜(—Kšœ)˜)Kšœ.˜.šžœ žœ˜Kšœžœ˜šœžœžœ˜Kšžœ &˜CKšžœžœžœ ˜C—Kšžœžœžœ ˜%Kšœ˜KšœM˜MKšœ˜K˜—Kšœ˜Kšœ˜—K˜š Ÿœžœžœžœžœ˜3šžœ0ž˜:Kšœžœžœ˜ Kšžœžœžœ˜—K˜—K˜šŸœžœ6žœ˜fKšœžœ˜Kšœžœ Πbc $˜RKšœ-˜-Kšœžœ ˜0Kšœ ˜5Kšœžœ 1˜IK˜šŸœžœ˜Kš <™<šžœ žœžœ˜šžœ ˜ Kšžœ=žœ˜Išžœ˜K˜?Kšœ<žœ˜PKšœ˜——Kšœ*˜*Kšœ˜K˜—K˜—K˜šŸœžœžœ žœ˜7Kšœ>™>šžœž˜šœ˜Kšœ1˜1Kšœ˜Kšžœžœžœ5˜GK˜—Kšžœ˜—K˜—K˜šŸœžœžœ žœžœžœžœ˜uKšžœžœ!žœ˜=Kšœ(˜(šžœ žœ˜KšœQ˜QKšœ&˜&K˜—K˜—K˜šŸœžœ˜K™UKšœ:™:Kšœ0™0Kšœ˜Kšœžœ-˜AKšžœžœ0žœ ˜ZKšœ5˜5Kšœ˜šžœžœžœ˜.šžœAžœ'žœ˜sKšœžœA˜KKšœP˜PKšž˜K˜—K˜—Kšœz˜zKšžœ˜K˜K˜—šŸœžœ˜!Kš (™(K˜š Ÿœžœžœžœžœ˜7Kš ?™?Kš žœžœ$žœžœ  ˜RKš žœžœ*žœžœ  ˜\Kšžœ0žœžœ ˜VKšžœ"žœžœ˜1šžœ ž˜K˜"Kšžœžœžœ˜—Kšžœžœ˜Kšœ˜K˜—š Ÿœžœžœžœžœ˜?Kšœj™jšžœžœ$žœ˜=Kšžœžœ  ˜—šžœžœ*žœ˜IKšžœžœ  ˜—Kšžœ"žœžœžœ˜8šžœ ž˜K˜"Kšžœžœ˜—šžœžœž˜šœ ˜ Kš žœžœžœžœžœ˜Bšžœž˜KšΠbf Ρbfk’£’œ˜Kšžœžœžœ˜—K˜—Kšžœžœžœ˜—Kšœ˜K˜—K™Kšœžœžœ˜Kšœ ˜ šžœž˜šœ ˜ šžœžœ  ˜0šžœžœžœžœ˜WKšœ.ΟbΠbk˜5K˜—šžœžœžœ˜EKšœ€₯˜K˜—K˜—šžœ ž˜Kšœ5žœ˜:KšœDžœ˜JKšžœžœ˜)—K˜—Kšœ˜Kšœ˜Kšžœ˜—Kšœžœ žœžœS˜„Kšœ ˜—K˜šŸœžœ˜"Kšœ€œ9™AKšœ5™5Kšœ žœ'˜7Kšœ˜šžœžœžœ2žœ˜^Kšœ˜Kšž˜K˜—Kšžœžœ ˜šžœžœ˜Kšœ ˜ Kšž˜K˜—šžœžœ+žœ!žœ˜jKš —™—Kšœ˜Kšž˜Kšœ ˜—šžœž˜šœ˜Kš %™%Kšœ žœ˜šžœ!ž˜(šžœžœžœ"žœ˜ZKš %™%Kšœ žœ˜Kšœ žœ˜'Kšœ žœ%˜3Kšœžœžœ˜šžœž˜Kšœ˜Kšœžœ˜ Kšžœ˜—šžœ*žœ!žœ˜VJ™ KšœI˜IK˜—KšœP˜PKšœ'˜'šžœžœžœ˜.šžœ5žœ˜=Kšœžœ5˜?KšœO˜OKšž˜K˜—K˜—šžœ F˜LK™KK™/š Ÿœžœžœžœžœ˜Ašžœžœž˜šœ ˜ Kš žœžœžœžœžœžœ˜[šžœž˜Kšœžœžœ˜!Kšžœ˜ —K˜—Kšžœ˜—K˜—Kšœ žœžœ˜š žœ žœ žœžœžœ$žœ˜lKšœžœ$˜8Kšœ žœ˜)Kšœ9žœ˜?Kšœ,˜,Kšœ6˜6Kšœ4˜4KšœJ˜JKšœ!˜!Kšž˜Kšœ˜—Kšžœ˜—KšœU˜UKšž˜K˜—Kšœ-˜-Kšžœ˜—Kšœ˜—Kšœ˜Kšžœ˜—K˜šžœ%žœ˜-Kš $™$šžœž˜Kšœ  ˜"šœ˜Kšœ#˜#Kšœ1˜1Kšœ˜KšœJ˜JKšœ"˜"Kšœ>˜>Kšœ?˜?K˜—šœ˜Kšœ#˜#Kšœ1˜1Kšœ˜Kšœ<˜J˜—šžœ žœ˜J˜+J˜BJ˜#J˜*Kšœ€œ˜1Jšœžœ˜J˜—šžœžœ˜š žœžœ5žΟi)œžœ˜}KšœžœW˜aK˜RKšœ€œ˜3K˜K˜!K˜—K˜—K˜)K˜—Kšžœžœ˜—šžœ žœžœžœ˜HKšœžœ0˜:K˜MKšœ˜—šžœžœ žœ#žœ˜?Kšœžœ(˜2KšœM˜MKšœ˜—šžœ˜Kšœ€œ˜3K˜wKšœ%˜%šœ™KšœX™X—šžœ ˜šžœ˜Kšœ žœ˜šžœžœ˜%K˜;K˜—K˜&K˜—šžœ˜K˜:šžœžœ˜%K˜YKšœ#˜#K˜—K˜——Kšœ+˜+K˜7K˜—K˜—Kšžœ˜—Kšžœ žœžœ˜(Kšœ ˜—K˜š Ÿœžœ žœžœžœ˜MKšœ žœ"˜2Jš 9™9Jš C™CKšžœ$žœžœ˜@šžœžœž˜šœ žœžœž˜)šœ˜Jš S™SKšžœ$žœžœ˜JKš žœ'žœžœ(žœžœ˜—Kšžœ˜Kšœ˜—Kšœ žœ˜?Kšœžœ˜=Kšœžœ˜7šœ ˜ Kšžœ"žœžœ˜H—šœ˜šžœ žœžœ˜3Kšœžœ3˜9Kšžœžœžœ˜ K˜—Kšžœ˜Kšœ˜—Kšœ œžœ˜NKšžœžœ˜ —šœ˜Kšžœ"žœžœ˜H—šœ˜Kšžœ"žœžœ˜H—Kšžœ˜—Kšžœ˜Kšœ˜—šŸœžœ7žœ˜iKšœ˜Kšœ6˜6Kšœžœ˜Kšœžœ ‘ $˜QK˜šŸ œžœžœžœ˜CKš Y™Yšœžœžœ ˜ Kšžœ˜Kšžœ/˜3—Kšœ>žœ˜RKšœ#˜#Kšžœžœ2žœ ˜VKšœ˜šžœž˜šœ ˜'KšœC˜CKšœE˜EKšœ$˜$KšœC˜CKšœ6 ˜SKš ™KšœC˜CKšœ,˜,Kšœ+˜+šžœ ž˜˜šžœžœ$žœ˜6Kšœ ˜ —Kšœ˜—šœ ˜ Kšœf %˜‹Kšœ žœ˜&KšœG˜GKšœž˜ Kšœ˜—Kšœ+žœ˜1šœ ˜ KšœM˜MKšœžœ˜ K˜—Kšœ œ˜5Kšžœ˜Kšžœ˜—K˜—Kšžœ ˜'—Kšœ ˜—K˜K™Kš žœžœ$žœžœžœ ˜yšžœ ž˜šœ˜Kšžœ2žœ ˜DKšœ˜Kš žœžœžœžœžœ ˜+K˜—˜šŸœžœ˜#KšœH˜HKšœžœ˜Kšœ žœ=˜JKšœ žœ5žœ ˜hšœ˜Kšœ>˜>KšœC˜C—šžœ8žœ˜@KšœžœU˜_Kšœ6˜6Kšœ%˜%K˜—Kšœ1˜1šžœ žœ˜Kšœ˜šœU˜UKšœE˜E—Kšœ*˜*šœI˜IKšœI˜I—K˜—šœ+˜+Kšœ9˜9—šœ8˜8Kšœ9˜9—KšœT˜TKšœC˜CKšœ2˜2Kšžœ žœžœ=˜PK˜—šŸœžœ˜"Kšœ žœ˜Kšœžœ˜šœC˜CKšœA˜AKšœ˜—Kšžœ$žœžœ ˜Pšžœ8žœ˜@KšœžœU˜_Kšœ6˜6Kšœ%˜%K˜—šœ8 $˜\Kšœ9˜9—K™KšœN ˜\Kšœ(˜(KšœG˜GKšœ2˜2Kšžœ žœžœ=˜PK˜—Kšœ˜Kšœ žœ'˜4Kšœžœžœ-˜;KšœDžœ˜OKšœ)˜)Kšœ)˜)šžœžœ˜Kšœ˜Kš žœžœžœžœžœž˜%K˜—Kšžœ$žœ ˜6Kšœ;˜;Kšœ ˜ šžœ žœžœžœ˜>šžœ-žœ#žœ˜[Kšœ˜Kšžœ˜K˜—š žœžœžœžœžœ˜ZKšœ˜Kšžœ˜K˜—K˜—šžœž˜˜Gšœ ˜ šžœž˜Kšœ4˜4Kšžœ!˜(——Kšœ0˜0Kšœ˜KšœS˜SKšœc˜cK˜—Kšœ ˜ Kšžœ˜—K˜—šœ˜Kšœ˜KšœE˜EKšœ ˜ Kšœ=˜=KšœB˜BKšœžœžœžœ ˜;K˜—šœ˜Kšœ˜KšœE˜EKšœ ˜ Kšœ=˜=KšœB˜BKšœ˜Kšœ!˜!K˜—šœ ˜ Kš "™"KšœG˜GKšœ˜KšœG˜GK˜—šœ ˜ Kš "™"Kšœ(˜(Kšœ,˜,Kšžœžœ ˜#šœ%˜%šœ˜Kšœ˜Kšœ/˜/Kšœ˜—Kšœ˜—K˜—šœ  ˜&šžœ/žœžœ˜>Kšœ4˜4Kšœ˜K˜—šžœ0žœžœ˜?Kšœ6˜6Kšœ˜K˜—K˜—˜Kšœžœžœ˜#Kšœ-žœ˜1Kšœ˜Kšœ žœ +˜SKšœ žœ=˜JKšœ žœ5žœ ˜hšŸœžœžœžœ˜.Kš ,™,˜8Kšœ?˜?—KšœC˜CKšœT˜TKšœ9˜9Kšœ€œ˜1K˜—Kšžœ%žœ ˜7K˜Kšœ;˜;Kšœ ˜ KšœC˜Cšžœ8žœ˜@K˜^KšœR˜RKšœ*˜*K˜—KšœB˜BKšœ#˜#KšœF˜FKšœ9˜9K˜šžœ žœ˜Kšœ[˜[KšœE˜EKšœI˜IKšœI˜IKšœE˜EKšœ€œ)˜IK˜—K˜šžœ žœžœ #˜JKšœ?  ˜KKšœ žœžœ˜$K˜CK˜šžœ žœžœžœ˜HKšœ.˜.K˜WKšœ<˜Kšžœ3˜9K˜K˜—š Ÿ œžœžœžœžœ˜CK™8K™>Kšžœ3˜9K˜—K˜š Ÿœžœžœžœžœ˜)Kšžœžœžœžœ ˜4Kšžœžœžœ˜K˜K˜—š Ÿœžœžœ žœžœžœ˜:Kšžœžœžœžœ ˜4šžœ ž˜Kšœžœ ˜Kšœžœ ˜Kšœžœ˜Kšžœžœ˜—K˜—K˜šŸœžœ%žœ˜]Kš‘™Kš ™Kšœžœ˜%Kšœ&˜&KšœAžœ ˜OKšœ)˜)Kšœ ˜ Kšœ˜Kšœ<˜˜>Kšžœžœžœ ˜1Kšœ9˜9K˜—šœ ˜ Kšœ%˜%Kšœ!˜!Kšœ˜KšœP˜PKšžœžœžœ ˜1Kšœ9˜9K˜—šœ ˜ Kšœ*˜*Kšœ!˜!Kšžœ žœžœ ˜!Kšœ˜šžœ#˜%Kšžœ)žœ˜2šžœ˜Kšœžœ&˜-Kšœ žœ<˜JKšžœ'™*Kšžœžœ ˜!Kšœ>˜>Kšœ'˜'šžœžœ˜Kš ™Kšœ&˜&Kšœ˜—Kšœ˜——KšœP˜PKšžœžœžœ ˜1Kšœ9˜9K˜—šœ˜Kšœ!˜!Kšœ$˜$Kšœ˜Kšžœ žœžœ ˜!Kšœ˜Kšžœžœžœ;˜LK˜—˜Kšœ+˜+Kšœ*˜*Kšœ!˜!Kšœ˜Kšžœ žœžœ ˜!KšœP˜PKšœO˜OK˜—Kšžœ˜—Kšžœžœžœ ˜Kšœ ˜—K˜šŸœžœ%žœ˜]Kš‘™Kš ™Kšœ˜Kšœ&˜&KšœAžœ ˜OKšœ)˜)Kšžœ € œžœ ˜&Kšžœžœžœ7˜Hšžœž˜šœ ˜ Kšœ$˜$Kšœ˜Kšœ žœ˜&Kšœ˜K˜—šœ ˜ Kšœ$˜$Kšœ˜Kšœ ˜ Kšœ˜K˜—šœ˜Kšœ)˜)Kšœ˜šžœ˜!Kšžœ!žœ˜*šžœ˜Kšœžœ&˜-Kšœ žœ<˜JKšœ-™-Kšžœžœ ˜!Kšœ:˜:Kšœ#˜#šžœžœ˜Kš ™Kšœ&˜&Kšœ˜—Kšœ˜——Kšœ˜K˜—šœ˜K˜ K˜—˜Kšœ$˜$Kšœ+˜+Kšœ˜Kšœ!žœ˜'K˜—Kšžœ˜—Kšžœžœžœ ˜Kšœ ˜—K˜š Ÿœžœžžœ žœžœžœ ˜OKš ™Kš ,™,šžœžœž˜šœžœžœžœ˜šžœ ˜ Kšžœžœžœ˜Kšžœžœ˜%——Kšœžœžœ˜Kšœžœžœ˜Kšžœžœ4˜E—K˜—K˜šŸœžœžœžœ˜;Kš ™šœžœ ˜Kšžœžœ˜ Kšžœ˜ —Kšœžœ˜K˜—K˜šŸœžœ3žœ˜cš Ÿœžœžœžœžœ˜*šžœ(žœ˜/Kšžœžœžœžœ˜3—K˜—Kšœ˜Kšœ6˜6KšœA˜AKšœ˜Kšžœžœ ˜$Kšœ˜Kšœ>˜>šžœ ž˜Kšœ+˜+šœ ˜ Kšœ™Kšœ?˜?šœ˜šœ˜Kšœ ˜ Kšœ.žœ˜4Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšœžœ˜ K˜—šœ ˜ Kš œžœžœ žœžœ˜CKšžœ žœ ˜Kšžœžœ ˜'šžœ žœ˜Kšœ(˜(KšœL˜LKšœžœ˜ K˜—šžœ˜Kš 9™9Kšœžœ˜Kšœžœ˜!Kšœžœ&˜0Kšžœ žœ ˜šžœ žœ˜Kšœ.™.šœ˜šœ˜Kšœ ˜ Kšœ˜Kšœ˜K˜—Kšœ˜Kšœ˜—Kšœ˜—K™!šœ˜šœ˜Kšœ ˜ Kšœ.žœ˜4Kšœ ˜ Kšœ˜—Kšœ˜Kšœ˜—Kšœžœ˜ K˜—Kšœ˜—šœ ˜ Kšœ žœ˜#KšœP˜PKš ,™,Kšœ˜—šœ˜Kšœ<˜˜B—Kšœ˜—K˜Kš œžœžœžœžœ˜3K˜š Ÿœžœžœžœžœžœ˜Dšžœ"žœž˜1šœžœ˜Kšžœžœžœ ˜+K˜—Kšžœ˜—šžœ"žœž˜1Kšœžœžœ žœ ˜%Kšžœ˜—Kšœ-˜-KšœH˜Hšœ)˜)šœ ˜ Kšœu˜uKšœ˜Kšœ˜—Kšœ˜—Kšœ!žœ˜CKšœ˜—K˜šŸ œžœžœžœ˜1Jš ,™,šžœ˜Kšžœ˜šžœ˜Kšœ0˜0Kšœžœ˜Kšœ˜Kšœ˜K˜——K˜—K˜šŸœžœžœ˜Jšžœžœ˜Kšžœžœ ˜(Kšžœ ˜!K˜—Kšœ ˜ šžœž˜Kšœ>˜>—Kšœ˜—K˜šŸ œžœžœžœ˜MKš &™&K˜š Ÿœžœžœžœžœžœ˜dKš (™(Kš '™'šžœž˜šœ˜Kšœ<˜