protected virtual AstNode _Optimize(AstNodeExprCast Cast) { //Console.WriteLine("Optimize.AstNodeExprCast: {0} : {1}", Cast.CastedType, Cast.Expr); // Dummy cast if (Cast.CastedType == Cast.Expr.Type) { //Console.WriteLine("Dummy Cast"); return(Cast.Expr); } // Double Cast else if (Cast.Expr is AstNodeExprCast) { //Console.WriteLine("Double Cast"); var FirstCastType = (Cast.Expr as AstNodeExprCast).CastedType; var SecondCastType = Cast.CastedType; if (FirstCastType.IsPrimitive && SecondCastType.IsPrimitive) { if (AstUtils.GetTypeSize(FirstCastType) >= AstUtils.GetTypeSize(SecondCastType)) { return(Optimize(new AstNodeExprCast(Cast.CastedType, (Cast.Expr as AstNodeExprCast).Expr))); } } } // Cast to immediate else if (Cast.Expr is AstNodeExprImm) { //Console.WriteLine("Cast to immediate"); return(new AstNodeExprImm(AstUtils.CastType((Cast.Expr as AstNodeExprImm).Value, Cast.CastedType))); } return(Cast); }
protected virtual AstNode _Optimize(AstNodeExprCast cast) { //Console.WriteLine("Optimize.AstNodeExprCast: {0} : {1}", Cast.CastedType, Cast.Expr); // Dummy cast if (cast.CastedType == cast.Expr.Type) { //Console.WriteLine("Dummy Cast"); return(cast.Expr); } // Double Cast var expr = cast.Expr as AstNodeExprCast; if (expr != null) { //Console.WriteLine("Double Cast"); var firstCastType = expr.CastedType; var secondCastType = cast.CastedType; if (firstCastType.IsPrimitive && secondCastType.IsPrimitive) { if (AstUtils.GetTypeSize(firstCastType) >= AstUtils.GetTypeSize(secondCastType)) { return(Optimize(new AstNodeExprCast(cast.CastedType, expr.Expr))); } } return(cast); } // Cast to immediate var imm = cast.Expr as AstNodeExprImm; if (imm != null) { //Console.WriteLine("Cast to immediate"); return(new AstNodeExprImm(AstUtils.CastType(imm.Value, cast.CastedType))); } return(cast); }
protected virtual AstNode _Optimize(AstNodeExprBinop binary) { //Console.WriteLine("Optimize.AstNodeExprBinop: {0} {1} {2}", Binary.LeftNode, Binary.Operator, Binary.RightNode); var leftImm = binary.LeftNode as AstNodeExprImm; var rightImm = binary.RightNode as AstNodeExprImm; var leftType = binary.LeftNode.Type; var rightType = binary.RightNode.Type; var Operator = binary.Operator; if (leftType == rightType) { if (AstUtils.IsTypeFloat(leftType)) { var type = leftType; if (leftImm != null && rightImm != null) { var leftValue = Convert.ToDouble(leftImm.Value); var rightValue = Convert.ToDouble(rightImm.Value); switch (Operator) { case "+": return(new AstNodeExprImm(AstUtils.CastType(leftValue + rightValue, type))); case "-": return(new AstNodeExprImm(AstUtils.CastType(leftValue - rightValue, type))); case "*": return(new AstNodeExprImm(AstUtils.CastType(leftValue * rightValue, type))); case "/": return(new AstNodeExprImm(AstUtils.CastType(leftValue / rightValue, type))); } } else if (leftImm != null) { var leftValue = Convert.ToInt64(leftImm.Value); switch (Operator) { case "|": if (leftValue == 0) { return(binary.RightNode); } break; case "+": if (leftValue == 0) { return(binary.RightNode); } break; case "-": if (leftValue == 0) { return(new AstNodeExprUnop("-", binary.RightNode)); } break; case "*": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); if (leftValue == 1) { return(binary.RightNode); } break; case "/": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); break; } } else if (rightImm != null) { var rightValue = Convert.ToInt64(rightImm.Value); switch (Operator) { case "|": if (rightValue == 0) { return(binary.LeftNode); } break; case "+": if (rightValue == 0) { return(binary.LeftNode); } break; case "-": if (rightValue == 0) { return(binary.LeftNode); } break; case "*": if (rightValue == 1) { return(binary.LeftNode); } break; case "/": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); break; } } } else { var unop = binary.RightNode as AstNodeExprUnop; if (unop != null) { var rightUnary = unop; if (Operator == "+" || Operator == "-") { if (rightUnary.Operator == "-") { return(new AstNodeExprBinop(binary.LeftNode, Operator == "+" ? "-" : "+", rightUnary.RightNode)); } } } var type = leftType; // Can optimize just literal values. if (leftImm != null && rightImm != null) { if (AstUtils.IsTypeSigned(leftType)) { var leftValue = Convert.ToInt64(leftImm.Value); var rightValue = Convert.ToInt64(rightImm.Value); switch (Operator) { case "+": return(new AstNodeExprImm(AstUtils.CastType(leftValue + rightValue, type))); case "-": return(new AstNodeExprImm(AstUtils.CastType(leftValue - rightValue, type))); case "*": return(new AstNodeExprImm(AstUtils.CastType(leftValue * rightValue, type))); case "/": return(new AstNodeExprImm(AstUtils.CastType(leftValue / rightValue, type))); case "<<": return(new AstNodeExprImm(AstUtils.CastType(leftValue << (int)rightValue, type))); case ">>": return(new AstNodeExprImm(AstUtils.CastType(leftValue >> (int)rightValue, type))); } } else { var leftValue = Convert.ToUInt64(leftImm.Value); var rightValue = Convert.ToUInt64(rightImm.Value); // Optimize adding 0 switch (Operator) { case "+": return(new AstNodeExprImm(AstUtils.CastType(leftValue + rightValue, type))); case "-": return(new AstNodeExprImm(AstUtils.CastType(leftValue - rightValue, type))); case "*": return(new AstNodeExprImm(AstUtils.CastType(leftValue * rightValue, type))); case "/": return(new AstNodeExprImm(AstUtils.CastType(leftValue / rightValue, type))); case "<<": return(new AstNodeExprImm(AstUtils.CastType(leftValue << (int)rightValue, type))); case ">>": return(new AstNodeExprImm(AstUtils.CastType(leftValue >> (int)rightValue, type))); } } } else if (leftImm != null) { var leftValue = Convert.ToInt64(leftImm.Value); switch (Operator) { case "&": if (leftValue == 0) { return(new AstNodeExprImm(0)); } break; case "|": if (leftValue == 0) { return(binary.RightNode); } break; case "+": if (leftValue == 0) { return(binary.RightNode); } break; case "-": if (leftValue == 0) { return(new AstNodeExprUnop("-", binary.RightNode)); } break; case "*": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); if (leftValue == 1) { return(binary.RightNode); } break; case "/": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); break; } } else if (rightImm != null) { var rightValue = Convert.ToInt64(rightImm.Value); switch (Operator) { case "0": if (rightValue == 0) { return(new AstNodeExprImm(0)); } break; case "|": if (rightValue == 0) { return(binary.LeftNode); } break; case "+": if (rightValue == 0) { return(binary.LeftNode); } if (rightValue < 0) { return(new AstNodeExprBinop(binary.LeftNode, "-", new AstNodeExprImm(AstUtils.Negate(rightImm.Value)))); } break; case "-": if (rightValue == 0) { return(binary.LeftNode); } break; case "*": if (rightValue == 1) { return(binary.LeftNode); } break; case "/": //if (RightValue == 0) throw(new Exception("Can't divide by 0")); if (rightValue == 1) { return(binary.LeftNode); } break; } } } // !AstUtils.IsTypeFloat(LeftType) } // Special optimizations if ((leftType == typeof(uint) || leftType == typeof(int)) && rightType == typeof(int) && rightImm != null) { var rightValue = Convert.ToInt64(rightImm.Value); if (Operator == ">>" && rightValue == 0) { return(binary.LeftNode); } } return(binary); }
protected virtual void _Generate(AstNodeExprImm item) { var itemType = AstUtils.GetSignedType(item.Type); var itemValue = item.Value; if (itemType.IsEnum) { itemType = itemType.GetEnumUnderlyingType(); itemValue = AstUtils.CastType(itemValue, itemType); } if ( itemType == typeof(int) || itemType == typeof(sbyte) || itemType == typeof(short) || itemType == typeof(bool) ) { var value = (int)Convert.ToInt64(itemValue); switch (value) { case -1: Emit(OpCodes.Ldc_I4_M1); break; case 0: Emit(OpCodes.Ldc_I4_0); break; case 1: Emit(OpCodes.Ldc_I4_1); break; case 2: Emit(OpCodes.Ldc_I4_2); break; case 3: Emit(OpCodes.Ldc_I4_3); break; case 4: Emit(OpCodes.Ldc_I4_4); break; case 5: Emit(OpCodes.Ldc_I4_5); break; case 6: Emit(OpCodes.Ldc_I4_6); break; case 7: Emit(OpCodes.Ldc_I4_7); break; case 8: Emit(OpCodes.Ldc_I4_8); break; default: Emit(OpCodes.Ldc_I4, value); break; } } else if (itemType == typeof(long) || itemType == typeof(ulong)) { Emit(OpCodes.Ldc_I8, Convert.ToInt64(itemValue)); } else if (itemType == typeof(IntPtr)) { #if false Emit(OpCodes.Ldc_I8, ((IntPtr)Item.Value).ToInt64()); Emit(OpCodes.Conv_I); #else if (Environment.Is64BitProcess) { Emit(OpCodes.Ldc_I8, ((IntPtr)item.Value).ToInt64()); Emit(OpCodes.Conv_I); } else { Emit(OpCodes.Ldc_I4, ((IntPtr)item.Value).ToInt32()); Emit(OpCodes.Conv_I); } #endif } else if (itemType == typeof(float)) { Emit(OpCodes.Ldc_R4, (float)item.Value); } else if (item.Value == null) { Emit(OpCodes.Ldnull); } else if (itemType == typeof(string)) { Emit(OpCodes.Ldstr, (string)item.Value); } else if (itemType == typeof(Type)) { Emit(OpCodes.Ldtoken, (Type)item.Value); Emit(OpCodes.Call, ((Func <RuntimeTypeHandle, Type>)Type.GetTypeFromHandle).Method); //IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) } else { throw new NotImplementedException($"Can't handle immediate type {itemType}"); } }
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)); }
protected virtual AstNode _Optimize(AstNodeExprBinop Binary) { //Console.WriteLine("Optimize.AstNodeExprBinop: {0} {1} {2}", Binary.LeftNode, Binary.Operator, Binary.RightNode); var LeftImm = (Binary.LeftNode as AstNodeExprImm); var RightImm = (Binary.RightNode as AstNodeExprImm); var LeftType = Binary.LeftNode.Type; var RightType = Binary.RightNode.Type; var Operator = Binary.Operator; if ((LeftType == RightType)) { if (AstUtils.IsTypeFloat(LeftType)) { var Type = LeftType; if ((LeftImm != null) && (RightImm != null)) { var LeftValue = Convert.ToDouble(LeftImm.Value); var RightValue = Convert.ToDouble(RightImm.Value); switch (Operator) { case "+": return(new AstNodeExprImm(AstUtils.CastType(LeftValue + RightValue, Type))); case "-": return(new AstNodeExprImm(AstUtils.CastType(LeftValue - RightValue, Type))); case "*": return(new AstNodeExprImm(AstUtils.CastType(LeftValue * RightValue, Type))); case "/": return(new AstNodeExprImm(AstUtils.CastType(LeftValue / RightValue, Type))); } } else if (LeftImm != null) { var LeftValue = Convert.ToInt64(LeftImm.Value); switch (Operator) { case "|": if (LeftValue == 0) { return(Binary.RightNode); } break; case "+": if (LeftValue == 0) { return(Binary.RightNode); } break; case "-": if (LeftValue == 0) { return(new AstNodeExprUnop("-", Binary.RightNode)); } break; case "*": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); if (LeftValue == 1) { return(Binary.RightNode); } break; case "/": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); break; } } else if (RightImm != null) { var RightValue = Convert.ToInt64(RightImm.Value); switch (Operator) { case "|": if (RightValue == 0) { return(Binary.LeftNode); } break; case "+": if (RightValue == 0) { return(Binary.LeftNode); } break; case "-": if (RightValue == 0) { return(Binary.LeftNode); } break; case "*": if (RightValue == 1) { return(Binary.LeftNode); } break; case "/": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); break; } } } else { if (Binary.RightNode is AstNodeExprUnop) { var RightUnary = Binary.RightNode as AstNodeExprUnop; if (Operator == "+" || Operator == "-") { if (RightUnary.Operator == "-") { return(new AstNodeExprBinop(Binary.LeftNode, (Operator == "+") ? "-" : "+", RightUnary.RightNode)); } } } var Type = LeftType; // Can optimize just literal values. if ((LeftImm != null) && (RightImm != null)) { if (AstUtils.IsTypeSigned(LeftType)) { var LeftValue = Convert.ToInt64(LeftImm.Value); var RightValue = Convert.ToInt64(RightImm.Value); switch (Operator) { case "+": return(new AstNodeExprImm(AstUtils.CastType(LeftValue + RightValue, Type))); case "-": return(new AstNodeExprImm(AstUtils.CastType(LeftValue - RightValue, Type))); case "*": return(new AstNodeExprImm(AstUtils.CastType(LeftValue * RightValue, Type))); case "/": return(new AstNodeExprImm(AstUtils.CastType(LeftValue / RightValue, Type))); case "<<": return(new AstNodeExprImm(AstUtils.CastType(LeftValue << (int)RightValue, Type))); case ">>": return(new AstNodeExprImm(AstUtils.CastType(LeftValue >> (int)RightValue, Type))); } } else { var LeftValue = Convert.ToUInt64(LeftImm.Value); var RightValue = Convert.ToUInt64(RightImm.Value); // Optimize adding 0 switch (Operator) { case "+": return(new AstNodeExprImm(AstUtils.CastType(LeftValue + RightValue, Type))); case "-": return(new AstNodeExprImm(AstUtils.CastType(LeftValue - RightValue, Type))); case "*": return(new AstNodeExprImm(AstUtils.CastType(LeftValue * RightValue, Type))); case "/": return(new AstNodeExprImm(AstUtils.CastType(LeftValue / RightValue, Type))); case "<<": return(new AstNodeExprImm(AstUtils.CastType(LeftValue << (int)RightValue, Type))); case ">>": return(new AstNodeExprImm(AstUtils.CastType(LeftValue >> (int)RightValue, Type))); } } } else if (LeftImm != null) { var LeftValue = Convert.ToInt64(LeftImm.Value); switch (Operator) { case "&": if (LeftValue == 0) { return(new AstNodeExprImm(0)); } break; case "|": if (LeftValue == 0) { return(Binary.RightNode); } break; case "+": if (LeftValue == 0) { return(Binary.RightNode); } break; case "-": if (LeftValue == 0) { return(new AstNodeExprUnop("-", Binary.RightNode)); } break; case "*": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); if (LeftValue == 1) { return(Binary.RightNode); } break; case "/": //if (LeftValue == 0) return new AstNodeExprImm(AstUtils.CastType(0, Type)); break; } } else if (RightImm != null) { var RightValue = Convert.ToInt64(RightImm.Value); switch (Operator) { case "0": if (RightValue == 0) { return(new AstNodeExprImm(0)); } break; case "|": if (RightValue == 0) { return(Binary.LeftNode); } break; case "+": if (RightValue == 0) { return(Binary.LeftNode); } if (RightValue < 0) { return(new AstNodeExprBinop(Binary.LeftNode, "-", new AstNodeExprImm(AstUtils.Negate(RightImm.Value)))); } break; case "-": if (RightValue == 0) { return(Binary.LeftNode); } break; case "*": if (RightValue == 1) { return(Binary.LeftNode); } break; case "/": //if (RightValue == 0) throw(new Exception("Can't divide by 0")); if (RightValue == 1) { return(Binary.LeftNode); } break; } } } // !AstUtils.IsTypeFloat(LeftType) } // Special optimizations if ((LeftType == typeof(uint) || LeftType == typeof(int)) && RightType == typeof(int)) { if (RightImm != null) { var RightValue = Convert.ToInt64(RightImm.Value); if (Operator == ">>" && (RightValue == 0)) { return(Binary.LeftNode); } } } return(Binary); }