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);
                }
            }
        }
Example #2
0
 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);
     }
 }
Example #3
0
        /// <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);
        }