public void VisitNAry(IExpr node, Scalar <float> data) { var other = data as Scalar <float> .NAry; if (other == null || node.GetType() != data.GetType()) { Arent(); } else { // at most one will make recursive calls foreach (var(n, o) in (node.Inputs, other.Inputs).Zip()) { VisitFloat(n, o); VisitFloatArray(n, o); } } }
public void Visit(IExpr expr, Compiler compiler) { if (expr is IConst) { VisitConst(expr as IConst, compiler); } else if (expr is IShared) { VisitShared(expr as IShared, compiler); } else if (expr is IVar) { VisitVar(expr as IVar, compiler); } else if (expr is XSlice) { VisitSlice(expr as XSlice, compiler); } else if (expr is IFor) { VisitFor(expr as IFor, compiler); } else if (expr is Tensor <float> .Elementwise) { VisitElementwise(expr as Tensor <float> .Elementwise, compiler); } else if (expr is Tensor <int> .Elementwise) { VisitElementwise(expr as Tensor <int> .Elementwise, compiler); } else if (expr is Tensor <double> .Elementwise) { VisitElementwise(expr as Tensor <double> .Elementwise, compiler); } else if (expr is IElementwise) { throw new NotImplementedException("VisitElementwise for " + expr.GetType()); } else { VisitNAry(expr, compiler); } }
/// <summary> /// 式を評価し、結果が代入されたレジスタ番号を返す /// 再帰し、再帰深度が深い順にEmitされる /// returntoはresultレジスタの既定値を設定可能、省略で新規生成 /// </summary> /// <param name="e">Expression</param> /// <returns>Result register number</returns> byte CompileExpr(IExpr e, bool isLocal = true, byte?returnto = null) { // _ と $ は特殊なので別処理 if (e.GetType() == typeof(Variable)) { var val = (Variable)e; if (val.Identity == "_" || val.Identity == "$") { return((byte)(returnsPointer ? 0x31 : 0x30)); } } // 使うレジスタ管理器 var resrpers = e.Type.GetType() == typeof(IntType) ? (isLocal ? ose.LocalRegister : ose.GlobalRegister) : (isLocal ? ose.LocalPegister : ose.GlobalPegister); // 使うレジスタDictionary var resrpdic = e.Type.GetType() == typeof(IntType) ? (isLocal ? lval : gval) : lfunc; // 返すレジスタ番号 var result = returnto == null?resrpers.Lock() : (byte)returnto; // 整数リテラル // 再帰はリテラルで帰結する if (e.GetType() == typeof(IntLiteral)) { ose.Emit(OSECode6.LoadImm, result, ((IntLiteral)e).Value); } // ラムダリテラル else if (e.GetType() == typeof(LambdaLiteral)) { var lambda = (LambdaLiteral)e; var lambdalab = ose.Labels.Lock(); var lambdaend = ose.Labels.Lock(); var args = lambda.Args.Zip(lambda.Type.ArgsType, Tuple.Create).ToArray(); var locals = args.Select(x => (x.Item2.GetType() == typeof(IntType) ? ose.LocalRegister : ose.LocalPegister).Lock()).ToArray(); ose.Emit(OSECode6.PLoadImm, result, lambdalab); ose.EmitMacro(Macro.Goto, new MacroValues(to => lambdaend)); ose.Emit(OSECode6.Label, 0x01, lambdalab); ose.Emit(0x3C, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00); ose.FuncRegister.Local(); ose.FuncPegister.Local(); var zipped = args.Zip(locals, Tuple.Create); foreach (var arg in zipped) { FulynOption.DebugWrite("lambda arg " + arg.Item1.Item1 + ": " + arg.Item2); ose.Emit(arg.Item1.Item2.GetType() == typeof(IntType) ? OSECode3.Copy : OSECode3.PCopy, arg.Item2, (arg.Item1.Item2.GetType() == typeof(IntType) ? ose.FuncRegister : ose.FuncPegister).Lock()); (arg.Item1.Item2.GetType() == typeof(IntType) ? lval : lfunc).Add(arg.Item1.Item1, arg.Item2); } CompileExpr(lambda.Expr, returnto: (byte)(lambda.Expr.Type.GetType() == typeof(IntType) ? 0x30 : 0x31)); ose.Emit(0x3D, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00); ose.EmitMacro(Macro.PGoto, new MacroValues(), 0x30); ose.Emit(OSECode6.Label, 0x01, lambdaend); ose.FuncRegister.Unlocal(); ose.FuncPegister.Unlocal(); args.Select(x => (x.Item2.GetType() == typeof(IntType) ? ose.LocalRegister : ose.LocalPegister)).Zip(locals, Tuple.Create).ForEach(x => x.Item1.Free(x.Item2)); zipped.ForEach(x => (x.Item1.Item2.GetType() == typeof(IntType) ? lval : lfunc).Remove(x.Item1.Item1)); } // 呼び出し else if (e.GetType() == typeof(Call)) { var call = (Call)e; // Pxxの場合、CallマクロではなくPCallマクロ var isPointer = lfunc.Any(x => x.Key == call.Identity); ose.FuncRegister.Local(); ose.FuncPegister.Local(); // 引数の式を再帰評価し、引数レジスタに代入 // まだEmitしていないので深度が深いほど先にEmitされる var argsreg = call.Args.Select(x => (x.Type.GetType() == typeof(IntType) ? ose.LocalRegister : ose.LocalPegister).Lock()).Zip(call.Args, Tuple.Create).ToArray(); foreach (var reg in argsreg) { CompileExpr(reg.Item2, isLocal, reg.Item1); } // 引数をR30 ~ R3B, P30 ~ P3Bに代入 foreach (var reg in argsreg) { if (reg.Item2.Type.GetType() == typeof(IntType)) { ose.Emit(OSECode3.Copy, ose.FuncRegister.Lock(), reg.Item1); } else { ose.Emit(OSECode3.PCopy, ose.FuncPegister.Lock(), reg.Item1); } } // 呼び出しをEmit if (isPointer) { ose.Emit(OSECode3.PCopy, 0x1F, 0x30); ose.EmitMacro(Macro.PCall, new MacroValues(return_label => ose.Labels.Lock()), lfunc.First(x => x.Key == call.Identity).Value); ose.Emit(OSECode3.PCopy, 0x30, 0x1F); } else { ose.Emit(OSECode3.PCopy, 0x1F, 0x30); ose.EmitMacro(Macro.Call, new MacroValues(return_label => ose.Labels.Lock(), func_label => gfunc.First(x => x.Key == call.Identity).Value)); ose.Emit(OSECode3.PCopy, 0x30, 0x1F); } // 引数レジスタはもう使用しないので、全解放 argsreg.ForEach(x => (x.Item2.Type.GetType() == typeof(IntType) ? ose.LocalRegister : ose.LocalPegister).Free(x.Item1)); ose.FuncRegister.Unlocal(); ose.FuncPegister.Unlocal(); // 結果をreturnレジスタにコピー、戻り値はR30 or P31に入ってくる ose.Emit(call.Type.GetType() == typeof(IntType) ? OSECode3.Copy : OSECode3.PCopy, result, call.Type.GetType() == typeof(IntType) ? (byte)0x30 : (byte)0x31); } // パターンマッチ // ラベルをたくさんたべるよ! else if (e.GetType() == typeof(Match)) { var match = (Match)e; // true-falseか、hoge-piyo-otherwiseかを調べる var isIf = match.Otherwise == null; // マッチ対象を再帰評価 var expr = CompileExpr(match.Expr, isLocal); // true-falseの時 if (isIf) { // マッチ終了ラベル var endif = ose.Labels.Lock(); // true処理開始 : thenラベル var then = ose.Labels.Lock(); // trueならばthenラベルに飛ぶ // こういう処理なのは、右辺を評価した時に命令数が膨れ上がってもいいように ose.Emit(OSECode2.Cond, expr); ose.EmitMacro(Macro.Goto, new MacroValues(to => then)); // false時の右辺を評価し、resultにコピー CompileExpr(match.Cases.First(x => (x.Item1 as Variable) != null && (x.Item1 as Variable).Identity == "false").Item2, isLocal, result); // マッチ終了へ ose.EmitMacro(Macro.Goto, new MacroValues(to => endif)); // thenラベル ose.Emit(OSECode6.Label, 0x01, then); // true時の右辺を評価し、resultにコピー CompileExpr(match.Cases.First(x => (x.Item1 as Variable) != null && (x.Item1 as Variable).Identity == "true").Item2, isLocal, result); // マッチ終了 ose.Emit(OSECode6.Label, 0x01, endif); } // hoge-piyo-otherwiseの時 else { // マッチ型のレジスタ管理器 var matchreg = match.Type.GetType() == typeof(IntType) ? ose.LocalRegister : ose.LocalPegister; // マッチ終了ラベル var endmatch = ose.Labels.Lock(); // otherwiseラベル var otherwise = ose.Labels.Lock(); // 各ケース用ラベル var cases = Enumerable.Range(0, match.Cases.Length).Select(x => ose.Labels.Lock()).ToArray(); // マッチ用テンポラリレジスタ1: 結果用 var temp = matchreg.Lock(); // マッチ用テンポラリレジスタ2: 比較用 var ismatch = ose.LocalRegister.Lock(); // 分岐部分 foreach (var x in match.Cases.Zip(cases, Tuple.Create)) { // ケースの左辺を評価 var left = CompileExpr(x.Item1.Item1, isLocal, temp); // exprとtempを比較し、ismatchに代入 ose.Emit(match.Type.GetType() == typeof(IntType) ? OSECode4.CompEq : OSECode4.PCompEq, ismatch, temp, expr); // 評価 ose.Emit(OSECode2.Cond, ismatch); // ケースのラベルに飛ぶ ose.EmitMacro(Macro.Goto, new MacroValues(to => x.Item2)); } // どれにもマッチしなかったらotherwiseに飛ぶ ose.EmitMacro(Macro.Goto, new MacroValues(to => otherwise)); // 評価部分 foreach (var x in match.Cases.Zip(cases, Tuple.Create)) { // ケースのラベル ose.Emit(OSECode6.Label, 0x01, x.Item2); // 右辺を評価し、resultにコピー CompileExpr(x.Item1.Item2, isLocal, result); // マッチ終了へ ose.EmitMacro(Macro.Goto, new MacroValues(to => endmatch)); } // otherwise ose.Emit(OSECode6.Label, 0x01, otherwise); // otherwise時の右辺を評価し、resultにコピー CompileExpr(match.Otherwise, isLocal, result); // マッチ終了 ose.Emit(OSECode6.Label, 0x01, endmatch); // テンポラリレジスタを解放 matchreg.Free(temp); ose.LocalRegister.Free(ismatch); } // マッチ対象式のレジスタはもう使用しないので、解放 (match.Expr.Type.GetType() == typeof(IntType) ? (isLocal ? ose.LocalRegister : ose.GlobalRegister) : (isLocal ? ose.LocalPegister : ose.GlobalPegister) ).Free(expr); } // 変数 else if (e.GetType() == typeof(Variable)) { var val = (Variable)e; resrpdic = e.Type.GetType() == typeof(IntType) ? (lval.Keys.Contains(val.Identity) ? lval : gval) : lfunc; var reg = resrpdic.First(x => x.Key == val.Identity).Value; // returnレジスタにコピー ose.Emit(e.Type.GetType() == typeof(IntType) ? OSECode3.Copy : OSECode3.PCopy, result, reg); } return(result); }