<<>> <> <> <> <> <> <<>> 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 bAddrC is address [except if addrNotYetTaken], accesses field with size sz at position start>> <<--assumes all alignment requirements ok>> 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> IF C2CEmit.IsDelayedDeref[bAddrC] THEN { <<--make sure size is ok !>> bAddrC ¬ C2CEmit.Deref[C2CEmit.TakeAddr[bAddrC, TRUE], base.bits]; }; c ¬ C2CEmit.MinPrecedence[bAddrC, primaryPrecedence]; IF start=0 AND base.bits=C2CTarget.bitsPerWord --sz=bitsPerWord!-- THEN RETURN; c ¬ C2CEmit.Cat[c, IO.PutFR1[".f%g", IO.int[start/C2CTarget.bitsPerWord]]]; c ¬ C2CEmit.SetPrecedence[c, primaryPrecedence]; RETURN }; IF addrNotYetTaken THEN bAddrC ¬ C2CEmit.TakeAddr[bAddrC, TRUE]; c ¬ C2CEmit.PreventCastingToWord[bAddrC]; c ¬ C2CEmit.MinPrecedence[c, unaryPrecedence]; IF start#0 THEN { unit: INT = 8; xsz: INT ¬ IF sz=0 THEN C2CTarget.PointeeBits[1]--size does not matter; take minimum ELSE MAX[unit, MIN[C2CTarget.bitsPerWord, sz]]; --size for indexing IF (start MOD xsz)#0 THEN CantHappen; c ¬ C2CEmit.CastRef[c, xsz]; c ¬ C2CEmit.Parentize[ C2CEmit.Cat[c, "+", C2CCodeUtils.ConstI[start/xsz]] ]; c ¬ C2CEmit.SetRef[c, xsz]; }; c ¬ C2CEmit.Deref[c, sz]; }; BoolDontCareBit: PROC [] RETURNS [BOOL ¬ FALSE] = { SELECT C2CBasics.ctxTop.seq[C2CBasics.ctxTop.idx].key FROM $BoolBitHackOk => 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[] = { <<--makes sure baseMode, baseAM, and, pseudoBaseSz are defined>> 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] = { <<--caller needs outside knowlede whether addr or base is loaded>> 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 [] = { <<--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]>> 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 [] = { <<--the nice and easy case of field access>> PeekCouldSimplyMask: PROC [] RETURNS [BOOL ¬ FALSE] = { <<--recognizes case where field is exactly right adjusted in word>> 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] = { <<--Case introduced to avoid taking address of local variables which would force local variable into memory >> 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]; }; <<--PlainFieldAsIndexing>> 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 [] = { <<--Caveat: Valid only in cases where varNode.bits is well defined >> <<--will not yet call C2CAddressingOps.ModizeArithCode >> 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 { <<--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>> HandleComplexMask[]; RETURN }; SELECT baseAM FROM plain, value, getAddr => { <<--baseAM: so the alignment will be ok>> unitBits: INT ¬ pointeeBits; WHILE unitBits<=C2CTarget.bitsPerWord DO IF varNode.bits<=unitBits AND (fieldLoc.start MOD unitBits)+varNode.bits<=unitBits THEN { <<--access field completely in one unit>> 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.bits> compensate ¬ C2CTarget.PointeeBits[fieldLoc.base.bits]-fieldLoc.base.bits }; cc.ec ¬ AccessUnitAddr[GenericBaseForField[], unitBits, unitOff, isAlreadyAddr]; cc.ec ¬ C2CEmit.Deref[cc.ec, unitBits]; IF varNode.bits=1 AND BoolDontCareBit[] THEN { IF C2CTarget.maxBitsForFastLiterals>unitBits-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 <<--Masking out part of word if left boundary of part starts at unit boundary>> <<--Use deref and shift instead of two shifts... >> 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 { <<--access field crossing wordboundary>> 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"]; }; <<--HandleFieldLoc>> SELECT requestedAM FROM assAddr, plain, getAddr => { <<--alignment ok!>> 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 => { <<--This might be somewhat inefficient>> GenericRHSForFieldLoc[]; cc ¬ C2CAddressingOps.ModizeArithCode[cc, reqMode, varNode.bits]; }; assBits => { <<--This might be somewhat inefficient>> 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]; <<--but requestedAM#assBitAddr>> 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 => { <<--but requestedAM#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 { 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 => { <<--??note: varNode.bits are defined, since rqAm in [maskNShift, value] >> GenericRHSForFieldLoc[]; }; value, maskNShift => { <<--note: varNode.bits are defined, since rqAm in [maskNShift, value] >> IF C2CTarget.PointeeBits[fieldLoc.base.bits] CantHappen; ENDCASE => CaseMissing; }; lHSMaskNShift => { VerySimpleVariable: PROC [node: IntCodeDefs.Node] RETURNS [BOOL] = { <<--Recognizes simple local variables which might be put into registers >> 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]; <