protected AstNodeExprLocal GetLocal(int index) { if (!Locals.ContainsKey(index)) { Locals[index] = AstLocal.Create(GetVTypeType(), "LocalVFPR" + index); } return(Ast.Local(Locals[index])); }
protected virtual void _Generate(AstNodeExprNewArray NewArray) { var TempArrayLocal = AstLocal.Create(NewArray.Type, "$TempArray"); Generate(new AstNodeExprImm(NewArray.Length)); Emit(OpCodes.Newarr, NewArray.ElementType); Emit(OpCodes.Stloc, _GetLocalBuilderFromAstLocal(TempArrayLocal)); for (int n = 0; n < NewArray.Length; n++) { Generate(new AstNodeStmAssign(new AstNodeExprArrayAccess(new AstNodeExprLocal(TempArrayLocal), n), NewArray.Values[n])); } Generate(new AstNodeExprLocal(TempArrayLocal)); }
private AstNodeExprLValue BranchFlag() { if (DynarecConfig.BranchFlagAsLocal) { if (_branchFlagLocal == null) { _branchFlagLocal = AstLocal.Create <bool>("BranchFlag"); } return(_ast.Local(_branchFlagLocal)); } else { return(_ast.BranchFlag()); } }
public void TestSimpleLocal() { var testLocal = AstLocal.Create <int>("TestLocal"); var func = _generatorIl.GenerateDelegate <Func <int> >("Test", new AstNodeStmContainer( new AstNodeStmAssign( new AstNodeExprLocal(testLocal), new AstNodeExprImm(123) ), new AstNodeStmReturn( new AstNodeExprLocal(testLocal) ) )); Assert.Equal(123, func()); }
protected virtual void _Generate(AstNodeExprTerop Terop) { if (Terop.True.Type != Terop.False.Type) { throw (new InvalidOperationException(String.Format("AstNodeExprTerop '?:' types must match {0} != {1}", Terop.True.Type, Terop.False.Type))); } var TernaryType = Terop.True.Type; var TernaryTempAstLocal = AstLocal.Create(TernaryType); Generate(new AstNodeStmIfElse( Terop.Cond, new AstNodeStmAssign(new AstNodeExprLocal(TernaryTempAstLocal), Terop.True), new AstNodeStmAssign(new AstNodeExprLocal(TernaryTempAstLocal), Terop.False) )); Generate(new AstNodeExprLocal(TernaryTempAstLocal)); }
protected virtual void _Generate(AstNodeExprTerop terop) { if (terop.True.Type != terop.False.Type) { throw new InvalidOperationException( $"AstNodeExprTerop '?:' types must match {terop.True.Type} != {terop.False.Type}"); } var ternaryType = terop.True.Type; var ternaryTempAstLocal = AstLocal.Create(ternaryType); Generate(new AstNodeStmIfElse( terop.Cond, new AstNodeStmAssign(new AstNodeExprLocal(ternaryTempAstLocal), terop.True), new AstNodeStmAssign(new AstNodeExprLocal(ternaryTempAstLocal), terop.False) )); Generate(new AstNodeExprLocal(ternaryTempAstLocal)); }
public void TestAstSwitch() { var Local = AstLocal.Create <int>("Local"); var Ast = ast.Statements( ast.Switch( ast.Local(Local), ast.Default(ast.Return("Nor One, nor Three")), ast.Case(1, ast.Return("One")), ast.Case(3, ast.Return("Three")) ), ast.Return("Invalid!") ); var Actual = GeneratorCSharp.GenerateString <GeneratorCSharp>(Ast); var Expected = @" { switch (Local) { case 1: return ""One""; break; case 3: return ""Three""; break; default: return ""Nor One, nor Three""; break; } return ""Invalid!""; } " ; Actual = new Regex(@"\s+").Replace(Actual, " ").Trim(); Expected = new Regex(@"\s+").Replace(Expected, " ").Trim(); Assert.AreEqual(Expected, Actual); }
public AstNodeStm MethodCacheInfoCallDynamicPc(AstNodeExpr pc, bool tailCall) { //if (_DynarecConfig.FunctionCallWithStaticReferences) //{ // var Call = (AstNodeExpr)ast.CallInstance(GetMethodCacheInfoAtPC(PC), (Action<CpuThreadState>)MethodCacheInfo.Methods.CallDelegate, ast.CpuThreadState); // if (TailCall) Call = ast.TailCall(Call as AstNodeExprCall); // return ast.Statement(Call); //} //else { var localCachedPc = Ast.Local(AstLocal.Create <uint>("CachedPC")); var localCachedFunction = Ast.Local(AstLocal.Create <Action <CpuThreadState> >("CachedFunction")); var localCalculatePc = Ast.Local(AstLocal.Create <uint>("CalculatePC")); var call = (AstNodeExpr)Ast.CallDelegate(localCachedFunction, Ast.CpuThreadStateExpr); var callStm = (AstNodeStm)Ast.Statement(call); if (tailCall) { callStm = Ast.Statements(Ast.Statement(Ast.TailCall((AstNodeExprCall)call)), Ast.Return()); } return(Ast.Statements( Ast.Assign(localCalculatePc, pc), Ast.If (Ast.Binary(localCachedPc, "!=", localCalculatePc), Ast.Statements( Ast.Assign(localCachedPc, localCalculatePc), Ast.Assign(localCachedFunction, Ast.CallInstance(Ast.CpuThreadStateExpr, (Func <uint, Action <CpuThreadState> >)CpuThreadStateMethods.GetFuncAtPc, pc)) ) ), callStm )); } }
public void TestAstSwitch() { var local = AstLocal.Create <int>("Local"); var ast = Ast.Statements( Ast.Switch( Ast.Local(local), Ast.Default(Ast.Return("Nor One, nor Three")), Ast.Case(1, Ast.Return("One")), Ast.Case(3, Ast.Return("Three")) ), Ast.Return("Invalid!") ); var actual = GeneratorCSharp.GenerateString <GeneratorCSharp>(ast); var expected = @" { switch (Local) { case 1: return ""One""; break; case 3: return ""Three""; break; default: return ""Nor One, nor Three""; break; } return ""Invalid!""; } " ; actual = new Regex(@"\s+").Replace(actual, " ").Trim(); expected = new Regex(@"\s+").Replace(expected, " ").Trim(); Assert.Equal(expected, actual); }
protected virtual void _Generate(AstNodeStmSwitch Switch) { var allCaseValues = Switch.Cases.Select(Case => Case.CaseValue); var caseValues = allCaseValues as IList <object> ?? allCaseValues.ToList(); if (caseValues.Count != caseValues.Distinct().Count()) { throw new Exception("Repeated case in switch!"); } // Check types and unique values. var endCasesLabel = AstLabel.CreateLabel("EndCasesLabel"); var defaultLabel = AstLabel.CreateLabel("DefaultLabel"); if (Switch.Cases.Length > 0) { var commonType = Switch.Cases.First().CaseValue.GetType(); if (Switch.Cases.Any(Case => Case.CaseValue.GetType() != commonType)) { throw new Exception("All cases should have the same type"); } var doneSpecialized = false; // Specialized constant-time integer switch (if possible) if (AstUtils.IsIntegerType(commonType)) { var commonMin = Switch.Cases.Min(Case => AstUtils.CastType <long>(Case.CaseValue)); var commonMax = Switch.Cases.Max(Case => AstUtils.CastType <long>(Case.CaseValue)); var casesLength = commonMax - commonMin + 1; // No processing tables greater than 4096 elements. if (casesLength <= 4096) { var labels = new AstLabel[casesLength]; for (var n = 0; n < casesLength; n++) { labels[n] = defaultLabel; } foreach (var Case in Switch.Cases) { var realValue = AstUtils.CastType <long>(Case.CaseValue); var offset = realValue - commonMin; labels[offset] = AstLabel.CreateLabel("Case_" + realValue); } /* * //var SwitchVarLocal = AstLocal.Create(AllCaseValues.First().GetType(), "SwitchVarLocal" + SwitchVarCount++); * //Generate(new AstNodeStmAssign(new AstNodeExprLocal(SwitchVarLocal), Switch.SwitchValue - new AstNodeExprCast(CommonType, CommonMin))); * //Generate(new AstNodeStmIfElse(new AstNodeExprBinop(new AstNodeExprLocal(SwitchVarLocal), "<", 0), new AstNodeStmGotoAlways(DefaultLabel))); * //Generate(new AstNodeStmIfElse(new AstNodeExprBinop(new AstNodeExprLocal(SwitchVarLocal), ">=", CasesLength), new AstNodeStmGotoAlways(DefaultLabel))); * //Generate(new AstNodeExprLocal(SwitchVarLocal)); */ Generate(Switch.SwitchValue - new AstNodeExprCast(commonType, commonMin)); Emit(OpCodes.Switch, labels); Generate(new AstNodeStmGotoAlways(defaultLabel)); foreach (var Case in Switch.Cases) { var realValue = AstUtils.CastType <long>(Case.CaseValue); var offset = realValue - commonMin; Generate(new AstNodeStmLabel(labels[offset])); { Generate(Case.Code); } Generate(new AstNodeStmGotoAlways(endCasesLabel)); } doneSpecialized = true; } else { // TODO: find a common shift and masks for all the values to reduce CasesLength. // TODO: On too large test cases, split them recursively in: // if (Var < Half) { switch(Var - LowerPartMin) { ... } } else { switch(Var - Half - UpperPartMin) { ... } } } } // Specialized switch for strings (checking length, then hash, then contents) else if (commonType == typeof(string)) { // TODO! } // Generic if/else if (!doneSpecialized) { var switchVarLocal = AstLocal.Create(caseValues.First().GetType(), "SwitchVarLocal" + _switchVarCount++); Generate(new AstNodeStmAssign(new AstNodeExprLocal(switchVarLocal), Switch.SwitchValue)); //Switch.Cases foreach (var Case in Switch.Cases) { var labelSkipThisCase = AstLabel.CreateLabel("LabelCase" + Case.CaseValue); Generate(new AstNodeStmGotoIfFalse(labelSkipThisCase, new AstNodeExprBinop(new AstNodeExprLocal(switchVarLocal), "==", new AstNodeExprImm(Case.CaseValue)))); Generate(Case.Code); Generate(new AstNodeStmGotoAlways(endCasesLabel)); Generate(new AstNodeStmLabel(labelSkipThisCase)); } } } Generate(new AstNodeStmLabel(defaultLabel)); if (Switch.CaseDefault != null) { Generate(Switch.CaseDefault.Code); } Generate(new AstNodeStmLabel(endCasesLabel)); }
public AstNodeStm Vcmp() { var vectorSize = _instruction.OneTwo; var cond = _instruction.Imm4; var cond2 = (ConditionEnum)cond; //bool NormalFlag = (Cond & 8) == 0; //bool NotFlag = (Cond & 4) != 0; //uint TypeFlag = (Cond & 3); var localCcTemp = _ast.Local(AstLocal.Create <bool>()); var localCcOr = _ast.Local(AstLocal.Create <bool>()); var localCcAnd = _ast.Local(AstLocal.Create <bool>()); return(_ast.Statements( _ast.Assign(localCcOr, false), _ast.Assign(localCcAnd, true), // TODO: CHECK THIS! _ast.AssignVcc(0, true), _ast.AssignVcc(1, true), _ast.AssignVcc(2, true), _ast.AssignVcc(3, true), _List(vectorSize, index => { AstNodeExpr expr; //bool UsedForAggregate; var left = VecVs[index]; var right = VecVt[index]; switch (cond2) { case ConditionEnum.VcFl: expr = _ast.Immediate(false); break; case ConditionEnum.VcEq: expr = _ast.Binary(left, "==", right); break; case ConditionEnum.VcLt: expr = _ast.Binary(left, "<", right); break; //case ConditionEnum.VC_LE: Expr = ast.Binary(Left, "<=", Right); break; case ConditionEnum.VcLe: expr = _ast.CallStatic((Func <float, float, bool>)MathFloat.IsLessOrEqualsThan, left, right); break; case ConditionEnum.VcTr: expr = _ast.Immediate(true); break; case ConditionEnum.VcNe: expr = _ast.Binary(left, "!=", right); break; //case ConditionEnum.VC_GE: Expr = ast.Binary(Left, ">=", Right); break; case ConditionEnum.VcGe: expr = _ast.CallStatic((Func <float, float, bool>)MathFloat.IsGreatOrEqualsThan, left, right); break; case ConditionEnum.VcGt: expr = _ast.Binary(left, ">", right); break; case ConditionEnum.VcEz: expr = _ast.Binary(_ast.Binary(left, "==", 0.0f), "||", _ast.Binary(left, "==", -0.0f)); break; case ConditionEnum.VcEn: expr = _ast.CallStatic((Func <float, bool>)MathFloat.IsNan, left); break; case ConditionEnum.VcEi: expr = _ast.CallStatic((Func <float, bool>)MathFloat.IsInfinity, left); break; case ConditionEnum.VcEs: expr = _ast.CallStatic((Func <float, bool>)MathFloat.IsNanOrInfinity, left); break; // Tekken Dark Resurrection case ConditionEnum.VcNz: expr = _ast.Binary(left, "!=", 0f); break; case ConditionEnum.VcNn: expr = _ast.Unary("!", _ast.CallStatic((Func <float, bool>)MathFloat.IsNan, left)); break; case ConditionEnum.VcNi: expr = _ast.Unary("!", _ast.CallStatic((Func <float, bool>)MathFloat.IsInfinity, left)); break; case ConditionEnum.VcNs: expr = _ast.Unary("!", _ast.CallStatic((Func <float, bool>)MathFloat.IsNanOrInfinity, left)); break; default: throw (new InvalidOperationException()); } return _ast.Statements(new List <AstNodeStm> { _ast.Assign(localCcTemp, expr), _ast.AssignVcc(index, localCcTemp), _ast.Assign(localCcOr, _ast.Binary(localCcOr, "||", localCcTemp)), _ast.Assign(localCcAnd, _ast.Binary(localCcAnd, "&&", localCcTemp)) }); }), _ast.AssignVcc(4, localCcOr), _ast.AssignVcc(5, localCcAnd) )); }