Ejemplo n.º 1
0
        public override Value VisitBinaryOpExpression([NotNull] BinaryOpExpressionContext context)
        {
            var lhs = context.Lhs.Accept(this);
            var rhs = context.Rhs.Accept(this);

            if (lhs == null || rhs == null)
            {
                return(null);
            }

            switch (context.Op)
            {
            case '<':
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan, lhs, rhs)
                          .RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case '^':
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow, lhs, rhs)
                       .RegisterName("powtmp"));
            }

            case '+':
                return(InstructionBuilder.FAdd(lhs, rhs).RegisterName("addtmp"));

            case '-':
                return(InstructionBuilder.FSub(lhs, rhs).RegisterName("subtmp"));

            case '*':
                return(InstructionBuilder.FMul(lhs, rhs).RegisterName("multmp"));

            case '/':
                return(InstructionBuilder.FDiv(lhs, rhs).RegisterName("divtmp"));

            default:
            {
                // User defined op?
                var opKind = context.GetOperatorInfo(ParserStack.Parser);
                if (opKind != OperatorKind.InfixLeftAssociative && opKind != OperatorKind.InfixRightAssociative)
                {
                    throw new ArgumentException($"Invalid binary operator {context.Op}", nameof(context));
                }

                string calleeName = $"$binary{context.Op}";
                var    function   = GetFunction(calleeName);
                if (function == null)
                {
                    throw new ArgumentException($"Unknown function reference {calleeName}", nameof(context));
                }

                var args = context.Args.Select(a => a.Accept(this)).ToList( );
                return(InstructionBuilder.Call(function, args).RegisterName("calltmp"));
            }
            }
        }
Ejemplo n.º 2
0
        public override Value Visit(ConditionalExpression conditionalExpression)
        {
            var result = LookupVariable(conditionalExpression.ResultVariable.Name);

            EmitLocation(conditionalExpression);
            var condition = conditionalExpression.Condition.Accept(this);

            if (condition == null)
            {
                return(null);
            }

            EmitLocation(conditionalExpression);

            var condBool = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, condition, Context.CreateConstant(0.0))
                           .RegisterName("ifcond");

            var function = InstructionBuilder.InsertBlock.ContainingFunction;

            var thenBlock     = function.AppendBasicBlock("then");
            var elseBlock     = function.AppendBasicBlock("else");
            var continueBlock = function.AppendBasicBlock("ifcont");

            InstructionBuilder.Branch(condBool, thenBlock, elseBlock);

            // generate then block instructions
            InstructionBuilder.PositionAtEnd(thenBlock);
            var thenValue = conditionalExpression.ThenExpression.Accept(this);

            if (thenValue == null)
            {
                return(null);
            }

            InstructionBuilder.Store(thenValue, result);
            InstructionBuilder.Branch(continueBlock);

            // generate else block
            InstructionBuilder.PositionAtEnd(elseBlock);
            var elseValue = conditionalExpression.ElseExpression.Accept(this);

            if (elseValue == null)
            {
                return(null);
            }

            InstructionBuilder.Store(elseValue, result);
            InstructionBuilder.Branch(continueBlock);

            // generate continue block
            InstructionBuilder.PositionAtEnd(continueBlock);

            // since the Alloca is created as a non-opaque pointer it is OK to just use the
            // ElementType. If full opaque pointer support was used, then the Lookup map
            // would need to include the type of the value allocated.
            return(InstructionBuilder.Load(result.ElementType, result)
                   .RegisterName("ifresult"));
        }
Ejemplo n.º 3
0
        public override Value VisitConditionalExpression([NotNull] ConditionalExpressionContext context)
        {
            EmitLocation(context);
            var condition = context.Condition.Accept(this);

            if (condition == null)
            {
                return(null);
            }

            var condBool = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, condition, Context.CreateConstant(0.0))
                           .RegisterName("ifcond");

            var function = InstructionBuilder.InsertBlock.ContainingFunction;

            var thenBlock     = Context.CreateBasicBlock("then", function);
            var elseBlock     = Context.CreateBasicBlock("else");
            var phiMergeBlock = Context.CreateBasicBlock("ifcont");

            InstructionBuilder.Branch(condBool, thenBlock, elseBlock);

            // generate then block
            InstructionBuilder.PositionAtEnd(thenBlock);
            var thenValue = context.ThenExpression.Accept(this);

            if (thenValue == null)
            {
                return(null);
            }

            InstructionBuilder.Branch(phiMergeBlock);

            // capture the insert in case generating thenExpression adds new blocks
            thenBlock = InstructionBuilder.InsertBlock;

            // generate else block
            function.BasicBlocks.Add(elseBlock);
            InstructionBuilder.PositionAtEnd(elseBlock);
            var elseValue = context.ElseExpression.Accept(this);

            if (elseValue == null)
            {
                return(null);
            }

            InstructionBuilder.Branch(phiMergeBlock);
            elseBlock = InstructionBuilder.InsertBlock;

            // generate PHI merge block
            function.BasicBlocks.Add(phiMergeBlock);
            InstructionBuilder.PositionAtEnd(phiMergeBlock);
            var phiNode = InstructionBuilder.PhiNode(function.Context.DoubleType)
                          .RegisterName("iftmp");

            phiNode.AddIncoming(thenValue, thenBlock);
            phiNode.AddIncoming(elseValue, elseBlock);
            return(phiNode);
        }
Ejemplo n.º 4
0
        public override Value?Visit(BinaryOperatorExpression binaryOperator)
        {
            binaryOperator.ValidateNotNull(nameof(binaryOperator));
            EmitLocation(binaryOperator);

            switch (binaryOperator.Op)
            {
            case BuiltInOperatorKind.Less:
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan
                                                     , binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                                     , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                                     ).RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case BuiltInOperatorKind.Pow:
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow
                                               , binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("powtmp"));
            }

            case BuiltInOperatorKind.Add:
                return(InstructionBuilder.FAdd(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("addtmp"));

            case BuiltInOperatorKind.Subtract:
                return(InstructionBuilder.FSub(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("subtmp"));

            case BuiltInOperatorKind.Multiply:
                return(InstructionBuilder.FMul(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("multmp"));

            case BuiltInOperatorKind.Divide:
                return(InstructionBuilder.FDiv(binaryOperator.Left.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               , binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr)
                                               ).RegisterName("divtmp"));

            case BuiltInOperatorKind.Assign:
                Alloca target = LookupVariable((( VariableReferenceExpression )binaryOperator.Left).Name);
                Value  value  = binaryOperator.Right.Accept(this) ?? throw new CodeGeneratorException(ExpectValidExpr);
                InstructionBuilder.Store(value, target);
                return(value);

            default:
                throw new CodeGeneratorException($"ICE: Invalid binary operator {binaryOperator.Op}");
            }
        }
Ejemplo n.º 5
0
        public override Value Visit(ConditionalExpression conditionalExpression)
        {
            var condition = conditionalExpression.Condition.Accept(this);

            if (condition == null)
            {
                return(null);
            }

            var condBool = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, condition, Context.CreateConstant(0.0))
                           .RegisterName("ifcond");

            var function = InstructionBuilder.InsertBlock.ContainingFunction;

            var thenBlock     = function.AppendBasicBlock("then");
            var elseBlock     = function.AppendBasicBlock("else");
            var continueBlock = function.AppendBasicBlock("ifcont");

            InstructionBuilder.Branch(condBool, thenBlock, elseBlock);

            // generate then block instructions
            InstructionBuilder.PositionAtEnd(thenBlock);
            var thenValue = conditionalExpression.ThenExpression.Accept(this);

            if (thenValue == null)
            {
                return(null);
            }

            InstructionBuilder.Branch(continueBlock);

            // capture the insert in case generating else adds new blocks
            var thenResultBlock = InstructionBuilder.InsertBlock;

            // generate else block
            InstructionBuilder.PositionAtEnd(elseBlock);
            var elseValue = conditionalExpression.ElseExpression.Accept(this);

            if (elseValue == null)
            {
                return(null);
            }

            InstructionBuilder.Branch(continueBlock);
            var elseResultBlock = InstructionBuilder.InsertBlock;

            // generate continue block
            InstructionBuilder.PositionAtEnd(continueBlock);
            var phiNode = InstructionBuilder.PhiNode(function.Context.DoubleType)
                          .RegisterName("ifresult");

            phiNode.AddIncoming((thenValue, thenResultBlock), (elseValue, elseResultBlock));
            return(phiNode);
        }
Ejemplo n.º 6
0
        public override Value Visit(BinaryOperatorExpression binaryOperator)
        {
            switch (binaryOperator.Op)
            {
            case BuiltInOperatorKind.Less:
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan
                                                     , binaryOperator.Left.Accept(this)
                                                     , binaryOperator.Right.Accept(this)
                                                     ).RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case BuiltInOperatorKind.Pow:
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow
                                               , binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("powtmp"));
            }

            case BuiltInOperatorKind.Add:
                return(InstructionBuilder.FAdd(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("addtmp"));

            case BuiltInOperatorKind.Subtract:
                return(InstructionBuilder.FSub(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("subtmp"));

            case BuiltInOperatorKind.Multiply:
                return(InstructionBuilder.FMul(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("multmp"));

            case BuiltInOperatorKind.Divide:
                return(InstructionBuilder.FDiv(binaryOperator.Left.Accept(this)
                                               , binaryOperator.Right.Accept(this)
                                               ).RegisterName("divtmp"));

            default:
                throw new CodeGeneratorException($"ICE: Invalid binary operator {binaryOperator.Op}");
            }
        }
Ejemplo n.º 7
0
        public override Value VisitBinaryOpExpression([NotNull] BinaryOpExpressionContext context)
        {
            var lhs = context.Lhs.Accept(this);
            var rhs = context.Rhs.Accept(this);

            if (lhs == null || rhs == null)
            {
                return(null);
            }

            switch (context.Op)
            {
            case '<':
            {
                var tmp = InstructionBuilder.Compare(RealPredicate.UnorderedOrLessThan, lhs, rhs)
                          .RegisterName("cmptmp");
                return(InstructionBuilder.UIToFPCast(tmp, InstructionBuilder.Context.DoubleType)
                       .RegisterName("booltmp"));
            }

            case '^':
            {
                var pow = GetOrDeclareFunction(new Prototype("llvm.pow.f64", "value", "power"));
                return(InstructionBuilder.Call(pow, lhs, rhs)
                       .RegisterName("powtmp"));
            }

            case '+':
                return(InstructionBuilder.FAdd(lhs, rhs).RegisterName("addtmp"));

            case '-':
                return(InstructionBuilder.FSub(lhs, rhs).RegisterName("subtmp"));

            case '*':
                return(InstructionBuilder.FMul(lhs, rhs).RegisterName("multmp"));

            case '/':
                return(InstructionBuilder.FDiv(lhs, rhs).RegisterName("divtmp"));

            default:
                throw new ArgumentException($"Invalid binary operator {context.Op}", nameof(context));
            }
        }
Ejemplo n.º 8
0
        /*
         * // Output for-loop as:
         * //   ...
         * //   start = startexpr
         * //   goto loop
         * // loop:
         * //   variable = phi [start, loopheader], [nextvariable, loopend]
         * //   ...
         * //   bodyexpr
         * //   ...
         * // loopend:
         * //   step = stepexpr
         * //   nextvariable = variable + step
         * //   endcond = endexpr
         * //   br endcond, loop, endloop
         * // outloop:
         */
        public override Value VisitForExpression([NotNull] ForExpressionContext context)
        {
            var    function  = InstructionBuilder.InsertBlock.ContainingFunction;
            string varName   = context.Initializer.Name;
            var    allocaVar = CreateEntryBlockAlloca(function, varName);

            // Emit the start code first, without 'variable' in scope.
            Value startVal = null;

            if (context.Initializer.Value != null)
            {
                startVal = context.Initializer.Value.Accept(this);
                if (startVal == null)
                {
                    return(null);
                }
            }
            else
            {
                startVal = Context.CreateConstant(0.0);
            }

            // store the value into allocated location
            InstructionBuilder.Store(startVal, allocaVar);

            // Make the new basic block for the loop header, inserting after current
            // block.
            var preHeaderBlock = InstructionBuilder.InsertBlock;
            var loopBlock      = Context.CreateBasicBlock("loop", function);

            // Insert an explicit fall through from the current block to the loopBlock.
            InstructionBuilder.Branch(loopBlock);

            // Start insertion in loopBlock.
            InstructionBuilder.PositionAtEnd(loopBlock);

            // Start the PHI node with an entry for Start.
            var variable = InstructionBuilder.PhiNode(Context.DoubleType)
                           .RegisterName(varName);

            variable.AddIncoming(startVal, preHeaderBlock);

            // Within the loop, the variable is defined equal to the PHI node.  If it
            // shadows an existing variable, we have to restore it, so save it now.
            NamedValues.TryGetValue(varName, out Alloca oldValue);
            NamedValues[varName] = allocaVar;

            // Emit the body of the loop.  This, like any other expr, can change the
            // current BB.  Note that we ignore the value computed by the body, but don't
            // allow an error.
            if (context.BodyExpression.Accept(this) == null)
            {
                return(null);
            }

            Value stepValue = Context.CreateConstant(1.0);

            // DEBUG: How does ANTLR represent optional context (Null or IsEmpty == true)
            if (context.StepExpression != null)
            {
                stepValue = context.StepExpression.Accept(this);
                if (stepValue == null)
                {
                    return(null);
                }
            }

            // Compute the end condition.
            Value endCondition = context.EndExpression.Accept(this);

            if (endCondition == null)
            {
                return(null);
            }

            var curVar = InstructionBuilder.Load(allocaVar)
                         .RegisterName(varName);
            var nextVar = InstructionBuilder.FAdd(curVar, stepValue)
                          .RegisterName("nextvar");

            InstructionBuilder.Store(nextVar, allocaVar);

            // Convert condition to a bool by comparing non-equal to 0.0.
            endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(1.0))
                           .RegisterName("loopcond");

            // Create the "after loop" block and insert it.
            var loopEndBlock = InstructionBuilder.InsertBlock;
            var afterBlock   = Context.CreateBasicBlock("afterloop", function);

            // Insert the conditional branch into the end of LoopEndBB.
            InstructionBuilder.Branch(endCondition, loopBlock, afterBlock);
            InstructionBuilder.PositionAtEnd(afterBlock);

            // Add a new entry to the PHI node for the backedge.
            variable.AddIncoming(nextVar, loopEndBlock);

            // Restore the unshadowed variable.
            if (oldValue != null)
            {
                NamedValues[varName] = oldValue;
            }
            else
            {
                NamedValues.Remove(varName);
            }

            // for expr always returns 0.0 for consistency, there is no 'void'
            return(Context.DoubleType.GetNullValue( ));
        }
Ejemplo n.º 9
0
        public override Value?Visit(ForInExpression forInExpression)
        {
            forInExpression.ValidateNotNull(nameof(forInExpression));
            EmitLocation(forInExpression);
            var function = InstructionBuilder.InsertFunction;

            if (function is null)
            {
                throw new InternalCodeGeneratorException("ICE: Expected block attached to a function at this point");
            }

            string varName   = forInExpression.LoopVariable.Name;
            Alloca allocaVar = LookupVariable(varName);

            // Emit the start code first, without 'variable' in scope.
            Value?startVal;

            if (forInExpression.LoopVariable.Initializer != null)
            {
                startVal = forInExpression.LoopVariable.Initializer.Accept(this);
                if (startVal is null)
                {
                    return(null);
                }
            }
            else
            {
                startVal = Context.CreateConstant(0.0);
            }

            // store the value into allocated location
            InstructionBuilder.Store(startVal, allocaVar);

            // Make the new basic block for the loop header.
            var loopBlock = function.AppendBasicBlock("loop");

            // Insert an explicit fall through from the current block to the loopBlock.
            InstructionBuilder.Branch(loopBlock);

            // Start insertion in loopBlock.
            InstructionBuilder.PositionAtEnd(loopBlock);

            // Within the loop, the variable is defined equal to the PHI node.
            // So, push a new scope for it and any values the body might set
            using (NamedValues.EnterScope( ))
            {
                EmitBranchToNewBlock("ForInScope");

                // Emit the body of the loop.  This, like any other expression, can change the
                // current BB.  Note that we ignore the value computed by the body, but don't
                // allow an error.
                if (forInExpression.Body.Accept(this) == null)
                {
                    return(null);
                }

                Value?stepValue = forInExpression.Step.Accept(this);
                if (stepValue == null)
                {
                    return(null);
                }

                // Compute the end condition.
                Value?endCondition = forInExpression.Condition.Accept(this);
                if (endCondition == null)
                {
                    return(null);
                }

                // since the Alloca is created as a non-opaque pointer it is OK to just use the
                // ElementType. If full opaque pointer support was used, then the Lookup map
                // would need to include the type of the value allocated.
                var curVar = InstructionBuilder.Load(allocaVar.ElementType, allocaVar)
                             .RegisterName(varName);
                var nextVar = InstructionBuilder.FAdd(curVar, stepValue)
                              .RegisterName("nextvar");
                InstructionBuilder.Store(nextVar, allocaVar);

                // Convert condition to a bool by comparing non-equal to 0.0.
                endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(0.0))
                               .RegisterName("loopcond");

                // Create the "after loop" block and insert it.
                var afterBlock = function.AppendBasicBlock("afterloop");

                // Insert the conditional branch into the end of LoopEndBB.
                InstructionBuilder.Branch(endCondition, loopBlock, afterBlock);
                InstructionBuilder.PositionAtEnd(afterBlock);

                // for expression always returns 0.0 for consistency, there is no 'void'
                return(Context.DoubleType.GetNullValue( ));
            }
        }
Ejemplo n.º 10
0
        public override Value?Visit(ConditionalExpression conditionalExpression)
        {
            conditionalExpression.ValidateNotNull(nameof(conditionalExpression));
            var result = LookupVariable(conditionalExpression.ResultVariable.Name);

            EmitLocation(conditionalExpression);
            var condition = conditionalExpression.Condition.Accept(this);

            if (condition == null)
            {
                return(null);
            }

            EmitLocation(conditionalExpression);

            var condBool = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, condition, Context.CreateConstant(0.0))
                           .RegisterName("ifcond");

            var function = InstructionBuilder.InsertFunction;

            if (function is null)
            {
                throw new InternalCodeGeneratorException("ICE: expected block that is attached to a function at this point");
            }

            var thenBlock     = function.AppendBasicBlock("then");
            var elseBlock     = function.AppendBasicBlock("else");
            var continueBlock = function.AppendBasicBlock("ifcont");

            InstructionBuilder.Branch(condBool, thenBlock, elseBlock);

            // generate then block instructions
            InstructionBuilder.PositionAtEnd(thenBlock);

            // InstructionBuilder.InserBlock after this point is !null
            Debug.Assert(InstructionBuilder.InsertBlock != null, "expected non-null InsertBlock");
            var thenValue = conditionalExpression.ThenExpression.Accept(this);

            if (thenValue == null)
            {
                return(null);
            }

            InstructionBuilder.Store(thenValue, result);
            InstructionBuilder.Branch(continueBlock);

            // generate else block
            InstructionBuilder.PositionAtEnd(elseBlock);
            var elseValue = conditionalExpression.ElseExpression.Accept(this);

            if (elseValue == null)
            {
                return(null);
            }

            InstructionBuilder.Store(elseValue, result);
            InstructionBuilder.Branch(continueBlock);

            // generate continue block
            InstructionBuilder.PositionAtEnd(continueBlock);

            // since the Alloca is created as a non-opaque pointer it is OK to just use the
            // ElementType. If full opaque pointer support was used, then the Lookup map
            // would need to include the type of the value allocated.
            return(InstructionBuilder.Load(result.ElementType, result)
                   .RegisterName("ifresult"));
        }
Ejemplo n.º 11
0
        public override Value Visit(ForInExpression forInExpression)
        {
            var    function = InstructionBuilder.InsertBlock.ContainingFunction;
            string varName  = forInExpression.LoopVariable.Name;

            // Emit the start code first, without 'variable' in scope.
            Value startVal;

            if (forInExpression.LoopVariable.Initializer != null)
            {
                startVal = forInExpression.LoopVariable.Initializer.Accept(this);
                if (startVal == null)
                {
                    return(null);
                }
            }
            else
            {
                startVal = Context.CreateConstant(0.0);
            }

            // Make the new basic block for the loop header, inserting after current
            // block.
            var preHeaderBlock = InstructionBuilder.InsertBlock;
            var loopBlock      = function.AppendBasicBlock("loop");

            // Insert an explicit fall through from the current block to the loopBlock.
            InstructionBuilder.Branch(loopBlock);

            // Start insertion in loopBlock.
            InstructionBuilder.PositionAtEnd(loopBlock);

            // Start the PHI node with an entry for Start.
            var variable = InstructionBuilder.PhiNode(Context.DoubleType)
                           .RegisterName(varName);

            variable.AddIncoming(startVal, preHeaderBlock);

            // Within the loop, the variable is defined equal to the PHI node.
            // So, push a new scope for it and any values the body might set
            using (NamedValues.EnterScope( ))
            {
                NamedValues[varName] = variable;

                // Emit the body of the loop.  This, like any other expression, can change the
                // current BB.  Note that we ignore the value computed by the body, but don't
                // allow an error.
                if (forInExpression.Body.Accept(this) == null)
                {
                    return(null);
                }

                Value stepValue = forInExpression.Step.Accept(this);
                if (stepValue == null)
                {
                    return(null);
                }

                var nextVar = InstructionBuilder.FAdd(variable, stepValue)
                              .RegisterName("nextvar");

                // Compute the end condition.
                Value endCondition = forInExpression.Condition.Accept(this);
                if (endCondition == null)
                {
                    return(null);
                }

                // Convert condition to a bool by comparing non-equal to 0.0.
                endCondition = InstructionBuilder.Compare(RealPredicate.OrderedAndNotEqual, endCondition, Context.CreateConstant(0.0))
                               .RegisterName("loopcond");

                // capture loop end result block for loop variable PHI node
                var loopEndBlock = InstructionBuilder.InsertBlock;

                // Create the "after loop" block and insert it.
                var afterBlock = function.AppendBasicBlock("afterloop");

                // Insert the conditional branch into the end of LoopEndBB.
                InstructionBuilder.Branch(endCondition, loopBlock, afterBlock);
                InstructionBuilder.PositionAtEnd(afterBlock);

                // Add a new entry to the PHI node for the back-edge.
                variable.AddIncoming(nextVar, loopEndBlock);

                // for expression always returns 0.0 for consistency, there is no 'void'
                return(Context.DoubleType.GetNullValue( ));
            }
        }