DIRECTORY C2CAccess, C2CAddressing, C2CAddressingOps, C2CBasics, C2CCodePlaces, C2CDefs, C2CEmit, C2CIntCodeUtils, C2CMain, C2CMode, C2CNames, C2CRunTime, C2CSingleFloat, C2CStateUtils, C2CTarget, IntCodeDefs, Rope; C2CSingleFloatImpl: CEDAR PROGRAM IMPORTS C2CAccess, C2CAddressingOps, C2CBasics, C2CEmit, C2CIntCodeUtils, C2CNames, C2CStateUtils, C2CTarget, Rope EXPORTS C2CSingleFloat = BEGIN OPEN IntCodeDefs, C2CAddressingOps, C2CDefs, C2CMain, C2CMode; ROPE: TYPE = Rope.ROPE; TrialCC: TYPE = RECORD [ ok: BOOL, cc: CodeCont ]; fail: TrialCC = [FALSE, [NIL, NIL, NIL]]; 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]] }; UseInline: PUBLIC PROC [] RETURNS [BOOL] = { RETURN [C2CAccess.params.supportInlineFloatingPoint] }; GoodToUseFloatType: PUBLIC PROC [n: IntCodeDefs.Node] RETURNS [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 => {}; }; TryLoadNodeAsFloat: PROC [node: Node] RETURNS [tc: TrialCC ¬ fail] = { IF node.bits#C2CTarget.bitsPerWord THEN RETURN; WITH node SELECT FROM applyNode: ApplyNode => WITH applyNode.proc SELECT FROM operNode: OperNode => tc ¬ TryApplyOperAsFloat[applyNode, operNode]; ENDCASE => {}; ENDCASE => {}; }; TryApplyOperAsFloat: PROC [xApp: ApplyNode, operNode: OperNode] RETURNS [tc: TrialCC ¬ fail] = { WITH operNode.oper SELECT FROM arithOp: ArithOper => { IF arithOp.class.precision#C2CTarget.bitsPerWord THEN RETURN; IF arithOp.class.kind#real THEN RETURN; SELECT arithOp.select FROM add, sub, mul, div, mod, neg, abs, min, max => { tc.cc ¬ SomeFloatArithOp[xApp, arithOp, TRUE]; tc.ok ¬ TRUE; }; ENDCASE => {}; }; convertOp: ConvertOper => { IF convertOp.from.precision#C2CTarget.bitsPerWord THEN RETURN; IF convertOp.to.precision#C2CTarget.bitsPerWord THEN RETURN; IF convertOp.to.kind#real THEN RETURN; tc.cc ¬ SomeFloatConvertOp[xApp, convertOp, TRUE]; tc.ok ¬ TRUE; }; ENDCASE => {}; }; FPTemporary: PROC [] RETURNS [name: Rope.ROPE] = { name ¬ C2CNames.InternalName["tf"]; C2CEmit.AppendCode[temporaryDeclarations, C2CEmit.Cat["float ", name, ";\n"]]; }; LoadAsFloat: PUBLIC PROC [node: IntCodeDefs.Node, simple: BOOL ¬ FALSE] RETURNS [cc: CodeCont] = { tc: TrialCC; IF node.bits#C2CTarget.bitsPerWord THEN ERROR C2CBasics.CantHappen; tc ¬ TryLoadNodeAsFloat[node]; IF tc.ok THEN { cc ¬ tc.cc; IF simple THEN cc ¬ ForceAFloatTemporary[cc]; } ELSE { cc ¬ LoadArithNode[node]; IF simple AND C2CEmit.GetAddressable[cc.ec] AND C2CIntCodeUtils.UseTemporaryIfReused[node] THEN { cc.ec ¬ C2CEmit.Cat[" *(float*) ", C2CEmit.TakeAddr[cc.ec, TRUE]]; cc ¬ ForceAFloatTemporary[cc]; } ELSE { cc.ec ¬ LoopholeWordWithTemporary[cc.ec, wordToFloat]; }; }; }; LoopholeTarget: TYPE = {floatToWord, wordToFloat}; LoopholeWordWithTemporary: PROC [c: Code, direction: LoopholeTarget] RETURNS [Code] = { temp, into: ROPE; IF direction=floatToWord THEN { into ¬ C2CTarget.word; temp ¬ FPTemporary[]; } ELSE { into ¬ "float"; temp ¬ C2CStateUtils.DeclareVariable[temporaryDeclarations, C2CTarget.bitsPerWord]; }; c ¬ C2CEmit.MinPrecedence[c, assignPrecedence]; c ¬ C2CEmit.Cat[temp, " = ", c, ", *("]; c ¬ C2CEmit.Cat[c, into, "*)&", temp]; RETURN [ C2CEmit.ParentizeAndLn[c] ]; }; LoopholeWord: PROC [c: Code, direction: LoopholeTarget] RETURNS [Code] = { IF C2CEmit.GetAddressable[c] THEN { into: ROPE ¬ IF direction=floatToWord THEN C2CTarget.word ELSE "float"; c ¬ C2CEmit.Cat["*(", into, "*)", C2CEmit.TakeAddr[c, TRUE]]; c ¬ C2CEmit.SetPrecedence[c, unaryPrecedence]; } ELSE { c ¬ LoopholeWordWithTemporary[c, direction]; }; RETURN [c]; }; SomeFloatCompareOp: PUBLIC PROC [xApp: IntCodeDefs.ApplyNode, compOp: IntCodeDefs.CompareOper] RETURNS [cc: C2CMain.CodeCont] = { cc1, cc2: CodeCont; op: ROPE; precedence: Precedence ¬ orderPrecedence; precision: INT ¬ compOp.class.precision; IF precision#C2CTarget.bitsPerWord THEN C2CBasics.CantHappen; IF compOp.class.kind#real THEN C2CBasics.CantHappen; IF precision {op ¬ " < "}; le => {op ¬ " <= "}; ge => {op ¬ " >= "}; gt => {op ¬ " > "}; eq => {op ¬ " == "; precedence ¬ equalityPrecedence}; ne => {op ¬ " != "; precedence ¬ equalityPrecedence}; ENDCASE => C2CBasics.CaseMissing; cc.ec ¬ C2CEmit.BinOp[cc1.ec, op, cc2.ec, precedence]; }; SomeFloatConvertOp: PUBLIC PROC [xApp: ApplyNode, convertOp: ConvertOper, leaveFloat: BOOL ¬ FALSE] RETURNS [cc: CodeCont] = { cc1, cc2: CodeCont; IF convertOp.to.precision#C2CTarget.bitsPerWord THEN C2CBasics.CantHappen; IF convertOp.from.precision#C2CTarget.bitsPerWord THEN C2CBasics.CantHappen; SELECT convertOp.to.kind FROM signed, unsigned, address => { IF convertOp.from.kind#real THEN C2CBasics.CantHappen; cc ¬ LoadAsFloat[xApp.args.first]; cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, primaryPrecedence]; SELECT convertOp.to.kind FROM signed => cc.ec ¬ C2CEmit.Cat["(int)", cc.ec]; unsigned => cc.ec ¬ C2CEmit.Cat["(unsigned)", cc.ec]; ENDCASE => C2CBasics.CantHappen; cc.ec ¬ C2CEmit.CastWord[cc.ec]; }; real => { cc ¬ LoadArithNode[xApp.args.first]; cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, primaryPrecedence]; SELECT convertOp.from.kind FROM signed => cc.ec ¬ C2CEmit.Cat["(float)(int)", cc.ec]; unsigned, address => cc.ec ¬ C2CEmit.Cat["(float)(unsigned)", cc.ec]; ENDCASE => C2CBasics.CantHappen; cc.ec ¬ C2CEmit.SetPrecedence[cc.ec, unaryPrecedence]; IF ~leaveFloat THEN cc.ec ¬ LoopholeWord[cc.ec, floatToWord]; }; ENDCASE => C2CBasics.CantHappen; }; ForceAFloatTemporary: PROC [cc: CodeCont] RETURNS [CodeCont] = { name: Rope.ROPE ¬ FPTemporary[]; cc.sc ¬ C2CEmit.Cat[cc.sc, name, " = ", cc.ec, ";\n"]; cc.ec ¬ C2CEmit.IdentCode[name]; RETURN [cc]; }; SomeFloatArithOp: PUBLIC PROC [xApp: ApplyNode, arithOp: ArithOper, leaveFloat: BOOL ¬ FALSE] RETURNS [cc: CodeCont] = { cc1, cc2: CodeCont; IF arithOp.class.precision#C2CTarget.bitsPerWord THEN C2CBasics.CantHappen; IF arithOp.class.kind#real THEN C2CBasics.CantHappen; SELECT arithOp.select FROM add, sub, mul, div, mod => { C2CIntCodeUtils.CheckArgCount[xApp.args, 2]; cc1 ¬ LoadAsFloat[node: xApp.args.first]; cc2 ¬ LoadAsFloat[node: xApp.args.rest.first]; cc.sc ¬ Cat2[cc1.sc, cc2.sc]; cc1.ec ¬ C2CEmit.MinPrecedence[cc1.ec, multiplicationPrecedence]; cc2.ec ¬ C2CEmit.MinPrecedence[cc2.ec, multiplicationPrecedence]; SELECT arithOp.select FROM add => {cc.ec ¬ C2CEmit.Cat[cc1.ec, " + ", cc2.ec]}; sub => {cc.ec ¬ C2CEmit.Cat[cc1.ec, " - ", cc2.ec]}; mul => {cc.ec ¬ C2CEmit.Cat[cc1.ec, " * ", cc2.ec]}; div => {cc.ec ¬ C2CEmit.Cat[cc1.ec, " / ", cc2.ec]}; ENDCASE => C2CBasics.CaseMissing; cc.ec ¬ C2CEmit.SetPrecedence[cc.ec, additionPrecedence]; }; neg => { C2CIntCodeUtils.CheckArgCount[xApp.args, 1]; cc ¬ LoadAsFloat[node: xApp.args.first]; cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, unaryPrecedence]; cc.ec ¬ C2CEmit.Cat[" - ", cc.ec]; cc.ec ¬ C2CEmit.SetPrecedence[cc.ec, additionPrecedence]; }; abs => { tempName: Rope.ROPE ¬ FPTemporary[]; C2CIntCodeUtils.CheckArgCount[xApp.args, 1]; cc ¬ LoadAsFloat[xApp.args.first]; cc.ec ¬ C2CEmit.MinPrecedence[cc.ec, unaryPrecedence]; cc.ec ¬ C2CEmit.CatCall[C2CStateUtils.MacroName[floatAbsMacro], cc.ec, ", ", tempName]; }; min, max => { Access: PROC [arg: Node] RETURNS [c: Code] = { cc2: CodeCont ¬ LoadAsFloat[arg]; cc.sc ¬ Cat2[cc.sc, cc2.sc]; c ¬ C2CEmit.MinPrecedence[cc2.ec, unaryPrecedence]; }; macroName: Rope.ROPE ¬ SELECT arithOp.select FROM min => C2CStateUtils.MacroName[fMinMacro], max => C2CStateUtils.MacroName[fMaxMacro] ENDCASE => ERROR; args: NodeList ¬ xApp.args; cc.ec ¬ Access[args.first]; args ¬ args.rest; WHILE args#NIL DO --we could improve this by not simply using a linear list tx: Rope.ROPE ¬ FPTemporary[]; ty: Rope.ROPE ¬ FPTemporary[]; c2: Code ¬ Access[args.first]; args ¬ args.rest; cc.ec ¬ C2CEmit.CatCall[macroName, cc.ec, ", ", c2, ", ", Rope.Cat[tx, ", ", ty]]; IF args#NIL THEN cc ¬ ForceAFloatTemporary[cc]; ENDLOOP; }; ENDCASE => ERROR C2CBasics.NotYetImpl; IF ~leaveFloat THEN cc.ec ¬ LoopholeWord[cc.ec, floatToWord]; }; floatAbsMacro: C2CStateUtils.Macro ¬ C2CStateUtils.DefineMacro["FABS", "(f, t) ( ((t=(f)) >= (float) 0.0) ? (t) : (- (t)) )" ]; fMinMacro: C2CStateUtils.Macro ¬ C2CStateUtils.DefineMacro["FMIN", "(x, y, tx, ty) ( (tx=((float) x)) <= (ty=((float) y)) ? tx : ty )" ]; fMaxMacro: C2CStateUtils.Macro ¬ C2CStateUtils.DefineMacro["FMAX", "(x, y, tx, ty) ( (tx=((float) x)) >= (ty=((float) y)) ? tx : ty )" ]; END. \ C2CSingleFloatImpl.mesa Copyright Σ 1988..1993 by Xerox Corporation. All rights reserved. Christian Jacobi, August 31, 1988 12:01:57 pm PDT Christian Jacobi, January 25, 1993 10:05 am PST Willie-s, February 17, 1992 12:42 pm PST --detour of using address for case of float --detour of using address for case of float --screws mode; leaves result as value; --if leaveFloat type is float else type is standard assumes cc.ec being floating point; assigns it into a temporary and returns temporary in ec --screws mode; leaves result as value; --if leaveFloat type is float else type is standard Κ ‚–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ Οeœ7™BKšœ1™1K™/K™(—K˜šΟk ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜K˜—šΟnœžœž˜!Kšžœk˜rKšžœ˜—šž˜Kšžœ:˜>K˜—Kšžœžœžœ˜šœ žœžœ˜Kšœžœ˜ Kšœ ˜ K˜—Kš œžœžœžœžœ˜)K˜šŸœžœžœ˜/Kšžœžœžœžœ˜Kšžœžœžœžœ˜Kšžœ˜Kšœ˜—K˜šŸ œž œžœžœ˜,Kšžœ.˜4K˜—K˜š Ÿœžœžœžœž œ˜NKšžœžœžœ˜,šžœžœž˜šœ˜šžœžœž˜šœ˜šžœžœž˜šœ˜šžœ/žœž˜Qšžœž˜Kšœ žœžœ˜.Kšžœ˜———Kšžœ˜——Kšžœ˜——Kšžœ˜—K˜—K˜šŸœžœžœ˜FKšžœ!žœžœ˜/šžœžœž˜šœ˜šžœžœž˜KšœD˜DKšžœ˜——Kšžœ˜—K˜—K˜šŸœžœ'žœ˜`šžœžœž˜šœ˜Kšžœ/žœžœ˜=Kšžœžœžœ˜'šžœž˜šœ0˜0Kšœ(žœ˜.Kšœžœ˜ K˜—Kšžœ˜—K˜—šœ˜Kšžœ0žœžœ˜>Kšžœ.žœžœ˜