public override IAstNode VisitForExpression([NotNull] ForExpressionContext context) { var initializer = ( LocalVariableDeclaration )context.Initializer.Accept(this); ForInExpression retVal; using (NamedValues.EnterScope( )) { Push(initializer); var step = ( IExpression )context.StepExpression?.Accept(this) ?? new ConstantExpression(default, 1.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( )); }