C2CCodeUtilsImpl.mesa
Copyright Ó 1987, 1988, 1990, 1991 by Xerox Corporation. All rights reserved.
Christian Jacobi, March 31, 1988 10:31:05 am PST
Christian Jacobi, October 7, 1992 10:54 am PDT
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<Rope.Length[r] THEN r ¬ Rope.Substr[r, 0, length];
RETURN [Rope.Cat["""", r, """"]]
}
ELSE {
ros: IO.STREAM ¬ IO.ROS[];
IO.PutChar[ros, '"];
FOR i: INT IN [0..length) DO
c: CHAR ~ Rope.Fetch[r, i];
SELECT TRUE FROM
allOctal => 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 i<intCacheSz THEN intCache[i] ELSE Convert.RopeFromInt[i]];
};
ConstI: PUBLIC PROC [c: INT] RETURNS [code: Code] = {
code ¬ C2CEmit.Cat[RopeFromInt[c]];
code ¬ C2CEmit.SetPrecedence[code, identPrecedence];
};
ConstC: PUBLIC PROC [c: CARD] RETURNS [code: Code] = {
r: ROPE ¬ IF c<cIntCacheSz THEN intCache[c] ELSE Convert.RopeFromCard[c];
code ¬ C2CEmit.Cat[r];
code ¬ C2CEmit.SetPrecedence[code, identPrecedence];
};
limit: CARD ¬ LAST[CARD]/2;
IsPowerOfTwo: PROC [i: CARD] RETURNS [shift: INT ¬ 0] = {
-- >0, 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 bits<C2CTarget.bitsPerWord THEN {
IF bits>C2CTarget.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];
};
IF rightSpares#0 THEN {
word ← C2CEmit.MinPrecedence[word, unaryPrecedence];
--masks bits bits of word starting with start
--no word boundary crossings!
word ← C2CEmit.Cat[" (unsigned) ", word, " >> ", ConstI[rightSpares]];
word ← C2CEmit.SetPrecedence[word, shiftPrecedence];
word ← C2CEmit.SetAddressable[word, FALSE];
};
IF leftSpares#0 THEN {
word ← C2CEmit.MinPrecedence[word, bitAndPrecedence];
word ← C2CEmit.Cat[word, " & ", Mask[bits]];
word ← C2CEmit.SetPrecedence[word, bitAndPrecedence];
word ← C2CEmit.SetAddressable[word, FALSE];
};
code ← word;
};
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<C2CTarget.bitsPerWord THEN ERROR;
END.