<<>> <> <> <> <> DIRECTORY C2CBasics, C2CEmit, C2CCodeUtils, C2CDefs, C2CTarget, Convert, IntCodeDefs, IO, Rope; C2CCodeUtilsImpl: CEDAR PROGRAM IMPORTS Convert, C2CBasics, C2CEmit, C2CTarget, IO, Rope EXPORTS C2CCodeUtils = BEGIN ROPE: TYPE = Rope.ROPE; Code: TYPE = C2CDefs.Code; CodeOrRope: TYPE = REF; knownBitsPerWord: NAT = 32; CString: PUBLIC PROC [r: ROPE] RETURNS [string: ROPE] = { MustEncode: PROC [c: CHAR] RETURNS [BOOL] = INLINE { SELECT c FROM <' , >='\177, C2CEmit.breakChar, '\\, '" => RETURN [TRUE]; ENDCASE => RETURN [FALSE] }; PutOctal: PROC [stream: IO.STREAM, c: CHAR] = INLINE { IO.PutChar[stream, '\\]; IO.PutChar[stream, '0 + (ORD[c]/64)]; IO.PutChar[stream, '0 + ((ORD[c] MOD 64)/8)]; IO.PutChar[stream, '0 + (ORD[c] MOD 8)]; }; allOctal: BOOL ¬ FALSE; cntOctal: INT ¬ 0; length: INT ¬ Rope.Length[r]; IF length>1 AND Rope.Fetch[r, length-1]=0c THEN { <<--get rid of trailing 0 since the c language will add one anyway>> length ¬ length-1; }; FOR i: INT IN [0..length) DO c: CHAR ~ Rope.Fetch[r, i]; IF MustEncode[c] THEN { cntOctal ¬ cntOctal+1; IF cntOctal>8 AND cntOctal*8>i THEN {allOctal ¬ TRUE; EXIT} }; ENDLOOP; IF cntOctal=0 THEN { IF length PutOctal[ros, c]; c=C2CEmit.breakChar => {IO.PutChar[ros, c]; IO.PutChar[ros, c]}; MustEncode[c] => PutOctal[ros, c]; ENDCASE => IO.PutChar[ros, c]; ENDLOOP; IO.PutChar[ros, '"]; RETURN [IO.RopeFromROS[ros]]; }; }; maskCache: REF ARRAY[0..knownBitsPerWord] OF ROPE ¬ NEW[ARRAY[0..knownBitsPerWord] OF ROPE ¬ ALL[NIL]]; Mask: PUBLIC PROC [i: INT] RETURNS [mask: ROPE¬NIL] = { n: INT ¬ i; IF i>C2CTarget.bitsPerWord OR i<0 THEN ERROR; <<--check whether mask is cached [most often true]>> IF maskCache[i]#NIL THEN RETURN [maskCache[i]]; <<--mask is not yet cached; compute it>> WHILE n>=3 DO n ¬ n-3; mask ¬ Rope.Concat["7", mask]; ENDLOOP; SELECT n FROM 2 => mask ¬ Rope.Concat["03", mask]; 1 => mask ¬ Rope.Concat["01", mask]; 0 => mask ¬ Rope.Concat["0", mask]; ENDCASE => ERROR; maskCache[i] ¬ Rope.Flatten[mask]; }; ComplexMask: PUBLIC PROC [ones, zeroes: INT] RETURNS [mask: ROPE¬NIL] = { IF zeroes<=0 THEN RETURN [Mask[ones]]; IF ones<=0 THEN { IF ones=0 THEN RETURN [ "0" ] ELSE ERROR; }; IF ones+zeroes>C2CTarget.bitsPerWord THEN ERROR; WHILE zeroes>=3 DO mask ¬ Rope.Concat[mask, "0"]; zeroes ¬ zeroes-3; ENDLOOP; SELECT zeroes FROM 0 => {}; 2 => { mask ¬ Rope.Concat["4", mask]; ones¬ones-1; }; 1 => { IF ones=1 THEN RETURN [Rope.Concat["02", mask]]; mask ¬ Rope.Concat["6", mask]; ones¬ones-2; }; ENDCASE => ERROR; WHILE ones>=3 DO ones ¬ ones-3; mask ¬ Rope.Concat["7", mask]; ENDLOOP; SELECT ones FROM 2 => mask ¬ Rope.Concat["03", mask]; 1 => mask ¬ Rope.Concat["01", mask]; 0 => mask ¬ Rope.Concat["0", mask]; ENDCASE => ERROR; }; RopeFromInt: PUBLIC PROC [i: INT] RETURNS [ROPE] = { RETURN [IF i >=0 AND i0, and, equals amount! if TRUE>> power: CARD ¬ 1; DO IF power>i THEN RETURN [-1]; IF power=i THEN RETURN [shift]; IF power>limit THEN RETURN [-1]; power ¬ power+power; shift ¬ shift+1; ENDLOOP; }; ConstMul: PUBLIC PROC [code: Code, factor: CARD] RETURNS [Code] = { <<--assume code to be expression>> code ¬ C2CEmit.MinPrecedence[code, multiplicationPrecedence]; --it is safer to parentize too often code ¬ C2CEmit.CastWord[code]; IF factor=0 THEN code ¬ ConstI[0] ELSE IF factor#1 THEN { shift: INT ¬ IsPowerOfTwo[factor]; IF shift>0 THEN { code ¬ C2CEmit.Cat["(", code, " << ", ConstI[shift], ")"]; code ¬ C2CEmit.SetPrecedence[code, parenPrecedence]; } ELSE { code ¬ C2CEmit.Cat[code, " * ", ConstC[factor]]; code ¬ C2CEmit.SetPrecedence[code, multiplicationPrecedence]; }; }; RETURN [code] }; ConstDiv: PUBLIC PROC [code: Code, divisor: CARD] RETURNS [Code] = { <<--assume code to be expression>> code ¬ C2CEmit.MinPrecedence[code, multiplicationPrecedence]; code ¬ C2CEmit.CastWord[code]; IF divisor=0 THEN ERROR C2CBasics.CantHappen ELSE IF divisor#1 THEN { shift: INT ¬ IsPowerOfTwo[divisor]; IF shift>0 THEN { code ¬ C2CEmit.Cat["(", code, " >> ", ConstI[shift], ")"]; code ¬ C2CEmit.SetPrecedence[code, parenPrecedence]; } ELSE { code ¬ C2CEmit.MinPrecedence[code, multiplicationPrecedence]; code ¬ C2CEmit.Cat[code, " / ", ConstC[divisor]]; code ¬ C2CEmit.SetPrecedence[code, multiplicationPrecedence]; }; }; RETURN [code] }; ConstMod: PUBLIC PROC [code: Code, divisor: CARD] RETURNS [Code] = { <<--assume code to be expression>> code ¬ C2CEmit.MinPrecedence[code, multiplicationPrecedence]; IF divisor=0 THEN ERROR C2CBasics.CantHappen ELSE IF divisor=1 THEN code ¬ ConstI[0] ELSE { shift: INT ¬ IsPowerOfTwo[divisor]; IF shift>0 THEN code ¬ MaskOut[code, shift] ELSE { code ¬ C2CEmit.CastWord[code]; code ¬ C2CEmit.Cat[code, " % ", ConstC[divisor]]; code ¬ C2CEmit.Parentize[code]; --who remembers such funny precedences }; }; RETURN [code] }; MaskOut: PUBLIC PROC [code: Code, bits: INT] RETURNS [Code] = { IF bits<=0 OR bits>C2CTarget.bitsPerWord THEN C2CBasics.CantHappen; IF bitsC2CTarget.maxBitsForFastAnd THEN { distance: ROPE ¬ intCache[C2CTarget.bitsPerWord-bits]; code ¬ C2CEmit.MinPrecedence[code, unaryPrecedence]; code ¬ C2CEmit.Cat[" (((unsigned)", code, " << ", distance]; code ¬ C2CEmit.Cat[code, ") >> ", distance, ") "]; RETURN [code]; }; code ¬ C2CEmit.MinPrecedence[code, additionPrecedence]; --be legible.. code ¬ C2CEmit.Cat[code, " & ", Mask[bits]]; code ¬ C2CEmit.SetPrecedence[code, bitAndPrecedence]; }; RETURN [code]; }; MaskNShift: PUBLIC PROC [word: Code, bits: INT, start: INT, wsz: INT] RETURNS [code: Code] = { <<--masks bits bits of word starting with start>> <<--no word boundary crossings!>> <<--wsz: size of word used>> rightSpares: INT ¬ wsz-(start+bits); -- ?? ENDIAN ! leftSpares: INT ¬ start; -- ?? ENDIAN ! leftShift: INT ¬ C2CTarget.bitsPerWord-rightSpares-bits; rightShift: INT ¬ C2CTarget.bitsPerWord-bits; IF bits+start>wsz THEN C2CBasics.CantHappen; --multi word; IF rightSpares=0 THEN RETURN [MaskOut[word, bits]]; code ¬ C2CEmit.MinPrecedence[word, unaryPrecedence]; code ¬ C2CEmit.Cat["(unsigned)", code]; IF leftShift>0 THEN { code ¬ C2CEmit.Cat["(", code, " << ", ConstI[leftShift], ")"]; }; IF rightShift>0 THEN { code ¬ C2CEmit.Cat["(", code, " >> ", ConstI[rightShift], ")"]; }; IF rightShift>0 OR leftShift>0 THEN { code ¬ C2CEmit.SetPrecedence[code, parenPrecedence]; }; <> <> <<--masks bits bits of word starting with start>> <<--no word boundary crossings!>> <> ", ConstI[rightSpares]];>> <> <> <<};>> <> <> <> <> <> <<};>> <> }; intCacheSz: INT = 40; cIntCacheSz: CARD = intCacheSz; intCache: REF ARRAY [0..intCacheSz) OF ROPE ¬ NEW[ARRAY [0..intCacheSz) OF ROPE]; IF knownBitsPerWord#C2CTarget.bitsPerWord THEN ERROR; maskCache[1] ¬ "1"; --make single digit masks non octal maskCache[2] ¬ "3"; maskCache[3] ¬ "7"; FOR i: INT IN [0..intCacheSz) DO intCache[i] ¬ Convert.RopeFromInt[i]; ENDLOOP; IF intCacheSz