/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { var rs = item as AST.ReturnStatement; if (rs == null) { return(item); } if (rs.ReturnExpression is EmptyExpression) { return(item); } var stm = new ExpressionStatement() { Expression = new AST.AssignmentExpression() { Left = new AST.MemberReferenceExpression() { Target = Method.ReturnVariable, Name = Method.ReturnVariable.Name, SourceExpression = rs.ReturnExpression.SourceExpression, SourceResultType = Method.ReturnVariable.CecilType }, Right = rs.ReturnExpression, SourceExpression = rs.ReturnExpression.SourceExpression, SourceResultType = Method.ReturnVariable.CecilType, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign } }; rs.PrependStatement(stm); stm.UpdateParents(); rs.ReplaceWith(new ReturnStatement() { ReturnExpression = new EmptyExpression() { SourceExpression = rs.ReturnExpression.SourceExpression, SourceResultType = Method.ReturnVariable.CecilType.LoadType(typeof(void)) }, }); return(stm); }
public static Expression ConvertExpression(RenderState render, Method method, Expression s, VHDLType target, Mono.Cecil.TypeReference targetsource, bool fromCast) { var svhdl = render.VHDLType(s); // Deal with pesky integers that overflow the 32bit VHDL specs if (IsTooLargeIntegerLiteral(s, target)) { svhdl = render.TypeScope.StdLogicVectorEquivalent(target); } // Already the real target type, just return it if (svhdl == target) { return(s); } // Stuff we do not care about if (!svhdl.IsStdLogicVector && !svhdl.IsUnsigned && !svhdl.IsSigned && svhdl.IsArray && target.IsArray && render.TypeScope.GetByName(svhdl.ElementName) == render.TypeScope.GetByName(target.ElementName)) { return(s); } // Array lengths var targetlengthstr = string.IsNullOrWhiteSpace(target.Alias) ? target.Length.ToString() : target.Alias + "'length"; if (target == VHDLTypes.SYSTEM_BOOL) { // Boolean to std_logic is fine if (string.Equals("STD_LOGIC", svhdl.Name, StringComparison.OrdinalIgnoreCase)) { return(s); } // Source is numeric, and output is bool if (svhdl.IsNumeric || svhdl.IsStdLogicVector) { var zero = new PrimitiveExpression() { SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType, Value = 0 }; var eval = new BinaryOperatorExpression() { Parent = s.Parent, Name = s.Name, SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType.LoadType(typeof(bool)), Left = s, Operator = ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.InEquality, Right = zero }; zero.Parent = eval; s.ReplaceWith(eval); s.Parent = eval; return(eval); } else if (svhdl == VHDLTypes.BOOL) { var truexp = new PrimitiveExpression() { Value = true, SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType.LoadType(typeof(bool)), }; var falseexp = new PrimitiveExpression() { Value = false, SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType.LoadType(typeof(bool)), }; var eval = new ConditionalExpression() { ConditionExpression = s, TrueExpression = truexp, FalseExpression = falseexp, SourceExpression = s.SourceExpression, SourceResultType = truexp.SourceResultType }; truexp.Parent = eval; falseexp.Parent = eval; s.ReplaceWith(eval); s.Parent = eval; return(eval); } else { throw new Exception(string.Format("Unexpected conversion from {0} to {1}", svhdl, target)); } } else if (svhdl == VHDLTypes.INTEGER && (target.IsStdLogicVector || target.IsNumeric)) { if (target.IsSigned && target.IsNumeric) { return(WrapExpression(render, s, string.Format("TO_SIGNED({0}, {1})", "{0}", targetlengthstr), target)); } else if (target.IsUnsigned && target.IsNumeric) { return(WrapExpression(render, s, string.Format("TO_UNSIGNED({0}, {1})", "{0}", targetlengthstr), target)); } else if (target.IsStdLogicVector) { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR(TO_UNSIGNED({0}, {1}))", "{0}", targetlengthstr), target)); } else { throw new Exception(string.Format("Unexpected conversion from {0} to {1}", svhdl, target)); } } else if (target.IsNumeric && !svhdl.IsEnum) { if (svhdl.IsStdLogicVector || svhdl.IsSigned || svhdl.IsUnsigned) { var str = "{0}"; var resized = false; Variable tmpvar = null; if (target.Length != svhdl.Length) { if (svhdl.IsVHDLSigned) { // Resizing with signed is bad because we may chop the upper bit resized = true; str = string.Format("SIGNED(resize(UNSIGNED({0}), {1}))", str, targetlengthstr); } else if (svhdl.IsVHDLUnsigned) { resized = true; str = string.Format("resize({0}, {1})", str, targetlengthstr); } else if (svhdl.IsSystemSigned) { // Resizing with signed is bad because we may chop the upper bit str = string.Format("SIGNED(resize(UNSIGNED({0}), {1}))", str, targetlengthstr); svhdl = render.TypeScope.NumericEquivalent(svhdl); resized = true; } else if (svhdl.IsSystemUnsigned) { str = string.Format("resize(UNSIGNED({0}), {1})", str, targetlengthstr); svhdl = render.TypeScope.NumericEquivalent(svhdl); resized = true; } else if (target.Length > svhdl.Length) { // This must be a variable as bit concatenation is only allowed in assignment statements: // http://stackoverflow.com/questions/209458/concatenating-bits-in-vhdl tmpvar = render.RegisterTemporaryVariable(method, targetsource); render.TypeLookup[tmpvar] = target; var iexp = new IdentifierExpression() { Name = tmpvar.Name, Target = tmpvar, SourceExpression = s.SourceExpression, SourceResultType = targetsource }; string wstr; if (render.Config.USE_EXPLICIT_CONCATENATION_OPERATOR) { wstr = string.Format("IEEE.STD_LOGIC_1164.\"&\"(\"{0}\", {1})", new string('0', target.Length - svhdl.Length), "{0}"); } else { wstr = string.Format("\"{0}\" & {1}", new string('0', target.Length - svhdl.Length), "{0}"); } s.ReplaceWith(iexp); var asstm = new ExpressionStatement() { Expression = new AssignmentExpression() { Left = iexp.Clone(), Right = new CustomNodes.ConversionExpression() { Expression = s, SourceExpression = s.SourceExpression, SourceResultType = targetsource, WrappingTemplate = wstr, }, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, SourceExpression = s.SourceExpression, SourceResultType = targetsource }, }; s.PrependStatement(asstm); asstm.UpdateParents(); resized = true; s = iexp; } } if (svhdl.IsVHDLSigned != target.IsSigned || svhdl.IsVHDLUnsigned != target.IsUnsigned) { str = string.Format("{1}({0})", str, target.IsSigned ? "SIGNED" : "UNSIGNED"); } if (target.Length != svhdl.Length && !resized) { str = string.Format("resize({0}, {1})", str, targetlengthstr); } return(WrapExpression(render, s, str, target)); } /*if (svhdl.IsStdLogicVector && target.IsSigned) * return new VHDLConvertedExpression(s, target, "SIGNED({0})"); * else if (svhdl.IsStdLogicVector && target.IsUnsigned) * return new VHDLConvertedExpression(s, target, "UNSIGNED({0})"); * else*/ throw new Exception(string.Format("Unexpected conversion from {0} to {1}", svhdl, target)); } else if (target.IsStdLogicVector) { if (svhdl.IsNumeric) { if (svhdl.Length == target.Length) { return(WrapExpression(render, s, "STD_LOGIC_VECTOR({0})", target)); } else { if (!fromCast) { Console.WriteLine("WARN: Incompatible array lengths, from {0} to {1}", svhdl, target); } //throw new Exception(string.Format("Incompatible array lengths, from {0} to {1}", svhdl, target)); if (target.Length < svhdl.Length && svhdl.IsNumericSigned) { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR(resize(UNSIGNED({0}), {1}))", "{0}", targetlengthstr), target)); } else { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR(resize({0}, {1}))", "{0}", targetlengthstr), target)); } } } else if (svhdl.IsStdLogicVector) { if (target.Length == svhdl.Length) { render.TypeLookup[s] = target; return(s); } if (!fromCast) { Console.WriteLine("WARN: Incompatible array lengths, from {0} to {1}", svhdl, target); } //throw new Exception(string.Format("Incompatible array lengths, from {0} to {1}", svhdl, target)); if (target.Length < svhdl.Length) { // If the expression is a simple identifier, we can select bits from it // otherwise we need to inject a variable with the expression // and select the required bits from it if (!(s is IdentifierExpression || s is MemberReferenceExpression || s is IndexerExpression)) { var tmp = render.RegisterTemporaryVariable(method, s.SourceResultType); render.TypeLookup[tmp] = svhdl; var aleft = new IdentifierExpression() { Name = tmp.Name, Target = tmp, SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType }; var aexp = new AssignmentExpression() { Left = aleft, Right = s, SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType }; var astm = new ExpressionStatement() { Expression = aexp, Parent = method, }; var iexp = new IdentifierExpression() { SourceExpression = s.SourceExpression, SourceResultType = s.SourceResultType, Target = tmp }; s.ReplaceWith(iexp); s.PrependStatement(astm); astm.UpdateParents(); return(WrapExpression(render, iexp, string.Format("{0}({1} downto 0)", "{0}", target.Length - 1), target)); } return(WrapExpression(render, s, string.Format("{0}({1} downto 0)", "{0}", target.Length - 1), target)); } else if (svhdl.IsSigned) { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR(resize(SIGNED({0}), {1}))", "{0}", targetlengthstr), target)); } else if (svhdl.IsUnsigned) { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR(resize(UNSIGNED({0}), {1}))", "{0}", targetlengthstr), target)); } else { var tmp = render.RegisterTemporaryVariable(method, targetsource); render.TypeLookup[tmp] = target; var iexp = new IdentifierExpression() { Name = tmp.Name, Target = tmp, SourceExpression = s.SourceExpression, SourceResultType = targetsource }; render.TypeLookup[iexp] = target; string wexpr; if (render.Config.USE_EXPLICIT_CONCATENATION_OPERATOR) { wexpr = string.Format("IEEE.STD_LOGIC_1164.\"&\"(\"{0}\", {1})", new string('0', target.Length - svhdl.Length), "{0}"); } else { wexpr = string.Format("\"{0}\" & {1}", new string('0', target.Length - svhdl.Length), "{0}"); } s.ReplaceWith(iexp); var asstm = new ExpressionStatement(); s.PrependStatement(asstm); var asexp = new AssignmentExpression() { Left = iexp.Clone(), Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, Right = new CustomNodes.ConversionExpression() { Expression = s, SourceExpression = s.SourceExpression, SourceResultType = targetsource, WrappingTemplate = wexpr }, SourceExpression = s.SourceExpression, SourceResultType = targetsource }; render.TypeLookup[asexp.Left] = target; render.TypeLookup[asexp.Right] = target; asexp.Left.SourceResultType = targetsource; asexp.Right.SourceResultType = targetsource; asstm.Expression = asexp; asstm.UpdateParents(); return(iexp); } } else if (svhdl.IsSigned || svhdl.IsUnsigned) { if (target.Length == svhdl.Length) { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR({0})", "{0}"), target)); } else { return(WrapExpression(render, s, string.Format("STD_LOGIC_VECTOR(resize({0}, {1}))", "{0}", targetlengthstr), target)); } } else { throw new Exception(string.Format("Unexpected conversion from {0} to {1}", svhdl.Name, target.Name)); } } else if (target == VHDLTypes.INTEGER && (svhdl.IsStdLogicVector || svhdl.IsNumeric)) { if (svhdl.IsNumeric) { return(WrapExpression(render, s, "TO_INTEGER({0})", target)); } if (svhdl.IsSigned) { return(WrapExpression(render, s, "TO_INTEGER(SIGNED({0}))", target)); } else { return(WrapExpression(render, s, "TO_INTEGER(UNSIGNED({0}))", target)); } } else if (target == VHDLTypes.INTEGER && (svhdl.IsSystemSigned || svhdl.IsSystemUnsigned)) { return(WrapExpression(render, s, "TO_INTEGER({0})", target)); } else if (target == VHDLTypes.BOOL && svhdl == VHDLTypes.SYSTEM_BOOL) { return(WrapInParenthesis(render, WrapExpression(render, s, "{0} = '1'", target))); } else if ((target.IsSigned || target.IsUnsigned) && svhdl.IsStdLogicVector) { if (target.Length == svhdl.Length) { return(WrapExpression(render, s, string.Format("{1}({0})", "{0}", target.IsSigned ? "SIGNED" : "UNSIGNED"), target)); } else { return(WrapExpression(render, s, string.Format("resize({1}({0}), {2})", "{0}", target.IsSigned ? "SIGNED" : "UNSIGNED", targetlengthstr), target)); } } else if ((target.IsSigned || target.IsUnsigned) && svhdl == VHDLTypes.INTEGER) { if (target.IsSigned) { return(WrapExpression(render, s, string.Format("TO_SIGNED({0}, {1})", "{0}", target.Length), target)); } else if (target.IsUnsigned) { return(WrapExpression(render, s, string.Format("TO_UNSIGNED({0}, {1})", "{0}", target.Length), target)); } else { throw new Exception("Unexpected case"); } } else if ((svhdl.IsSigned || svhdl.IsUnsigned) && (target.IsSigned || target.IsUnsigned)) { if (target.Length == svhdl.Length) { if (svhdl.IsSigned == target.IsSigned) { return(s); } else { return(WrapExpression(render, s, string.Format("{1}({0})", "{0}", target.IsSigned ? "SIGNED" : "UNSIGNED"), target)); } } else { if (svhdl.IsSigned == target.IsSigned) { return(WrapExpression(render, s, string.Format("resize({0}, {1})", "{0}", targetlengthstr), target)); } else if (svhdl.IsSigned && svhdl.Length > target.Length) { return(WrapExpression(render, s, string.Format("resize(UNSIGNED({0}), {1})", "{0}", targetlengthstr), target)); } else { return(WrapExpression(render, s, string.Format("{2}(resize({0}, {1}))", "{0}", targetlengthstr, target.IsSigned ? "SIGNED" : "UNSIGNED"), target)); } } } else if (target.IsEnum && (svhdl.IsSigned || svhdl.IsUnsigned || svhdl == VHDLTypes.INTEGER)) { if (target.IsIrregularEnum) { return(WrapExpression(render, s, string.Format("fromValue_{1}({0})", svhdl == VHDLTypes.INTEGER ? "{0}" : "TO_INTEGER({0})", target.ToSafeVHDLName()), target)); } else { return(WrapExpression(render, s, string.Format("{1}'VAL({0})", svhdl == VHDLTypes.INTEGER ? "{0}" : "TO_INTEGER({0})", target.ToSafeVHDLName()), target)); } } else if (svhdl.IsEnum && (target.IsSigned || target.IsUnsigned || target == VHDLTypes.INTEGER)) { Expression wrapped; if (target.IsIrregularEnum) { wrapped = WrapExpression(render, s, string.Format("toValue_{1}({0})", "{0}", svhdl.ToSafeVHDLName()), target); } else { wrapped = WrapExpression(render, s, string.Format("{1}'POS({0})", "{0}", svhdl.ToSafeVHDLName()), target); } render.TypeLookup[wrapped] = VHDLTypes.INTEGER; if (target != VHDLTypes.INTEGER) { wrapped = ConvertExpression(render, method, wrapped, target, targetsource, false); } return(wrapped); } else { throw new Exception(string.Format("Unexpected target type: {0} for source: {1}", target, svhdl)); } }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { var stm = item as AST.ForStatement; if (stm == null) { return(item); } if (m_processed.Contains(stm)) { return(item); } m_processed.Add(stm); Tuple <int, int, int> loopedges = null; try { loopedges = stm.GetStaticForLoopValues(); } catch { return(item); } var incr = loopedges.Item3; if (incr == 1) { return(item); } var tmp = State.RegisterTemporaryVariable(Method, stm.LoopIndex.CecilType); State.TypeLookup[tmp] = VHDLTypes.INTEGER; // Find the first expression, so we can inject the assignment before it var firstexp = stm.LoopBody.All().OfType <Expression>().First(); // Replace all the references foreach (var x in stm.All().OfType <Expression>()) { var target = x.GetTarget(); if (target == stm.LoopIndex) { x.SetTarget(tmp); } } var exp = firstexp.SourceExpression; // Inject the assignment var nstm = new ExpressionStatement() { Expression = new AssignmentExpression() { Left = new IdentifierExpression() { Name = tmp.Name, Target = tmp, SourceExpression = exp, SourceResultType = tmp.CecilType }, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, Right = new BinaryOperatorExpression() { Left = new IdentifierExpression() { Name = stm.LoopIndex.Name, Target = stm.LoopIndex, SourceExpression = exp, SourceResultType = stm.LoopIndex.CecilType }, Operator = ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Multiply, Right = new PrimitiveExpression() { Value = incr, SourceResultType = tmp.CecilType, SourceExpression = exp, }, SourceExpression = exp, SourceResultType = tmp.CecilType }, SourceExpression = exp, SourceResultType = tmp.CecilType } }; nstm.UpdateParents(); foreach (var x in nstm.All().OfType <Expression>()) { State.TypeLookup[x] = VHDLTypes.INTEGER; } stm.LoopBody.PrependStatement(nstm); //Do not fix again stm.Increment = new AssignmentExpression( new IdentifierExpression(stm.LoopIndex), new BinaryOperatorExpression( new IdentifierExpression(stm.LoopIndex), ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add, new PrimitiveExpression(1, tmp.CecilType) ) { SourceResultType = tmp.CecilType } ) { Parent = stm, SourceResultType = tmp.CecilType }; stm.Condition = new BinaryOperatorExpression( new IdentifierExpression(stm.LoopIndex), ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.LessThan, new PrimitiveExpression(loopedges.Item2 / loopedges.Item3, tmp.CecilType.Module.ImportReference(typeof(int))) ) { Parent = stm, SourceResultType = tmp.CecilType.Module.ImportReference(typeof(bool)) }; return(nstm); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { var uoe = el as UnaryOperatorExpression; if (uoe == null) { return(el); } var incr = new[] { ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Increment, ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Decrement, ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostIncrement, ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostDecrement }.Contains(uoe.Operator); if (!incr) { return(el); } var cnst = new PrimitiveExpression() { SourceExpression = uoe.SourceExpression, SourceResultType = uoe.SourceResultType.LoadType(typeof(int)), Value = 1 }; State.TypeLookup[cnst] = VHDLTypes.INTEGER; var boe = new BinaryOperatorExpression() { Left = uoe.Operand.Clone(), Right = cnst, SourceExpression = uoe.SourceExpression, SourceResultType = uoe.SourceResultType, Operator = uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Decrement || uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostDecrement ? ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Subtract : ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add }; State.TypeLookup[boe] = State.VHDLType(uoe.Operand); // Prepare an assignment expresion var ase = new AssignmentExpression() { Left = uoe.Operand.Clone(), Right = boe, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, SourceExpression = uoe.SourceExpression, SourceResultType = uoe.SourceResultType }; var exps = new ExpressionStatement() { Expression = ase, }; exps.UpdateParents(); if (uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostIncrement || uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostDecrement) { if (uoe.Parent is ExpressionStatement || uoe.Parent is ForStatement) { // Simple "i++;" statements are replaced with i = i + 1 uoe.ReplaceWith(ase); return(ase); } else { // More complicated are split uoe.AppendStatement(exps); // Remove the operator now, as the assignment happens after uoe.ReplaceWith(uoe.Operand); return(exps); } } else { // If the left-hand-side is also the target, we can just replace // with the binary operator without needing a temporary variable if (uoe.Operand.GetTarget() != null && boe.Parent is AssignmentExpression && ((AssignmentExpression)boe.Parent).Left.GetTarget() == uoe.Operand.GetTarget()) { uoe.ReplaceWith(boe); return(boe); } else { // TODO: Can have more complex cases where // the expression is use multiple times in the same statement and some need the updated version, // others the non-updated version. // To support this, we need to seek for references to the target // and replace the references with the correct pre/post versions uoe.PrependStatement(exps); uoe.ReplaceWith(boe); return(boe); } } }