private void EmitBranchToNewBlock(string blockName) { var newBlock = InstructionBuilder.InsertBlock.ContainingFunction.AppendBasicBlock(blockName); InstructionBuilder.Branch(newBlock); InstructionBuilder.PositionAtEnd(newBlock); }
private Function DefineFunction(Function function, ExpressionContext body) { if (!function.IsDeclaration) { throw new ArgumentException($"Function {function.Name} cannot be redefined", nameof(function)); } var basicBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(basicBlock); NamedValues.Clear( ); foreach (var arg in function.Parameters) { NamedValues[arg.Name] = arg; } var funcReturn = body.Accept(this); if (funcReturn == null) { function.EraseFromParent( ); return(null); } InstructionBuilder.Return(funcReturn); function.Verify( ); return(function); }
public override Value Visit(FunctionDefinition definition) { var function = GetOrDeclareFunction(definition.Signature); if (!function.IsDeclaration) { throw new CodeGeneratorException($"Function {function.Name} cannot be redefined in the same module"); } try { var entryBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(entryBlock); using (NamedValues.EnterScope( )) { foreach (var param in definition.Signature.Parameters) { NamedValues[param.Name] = function.Parameters[param.Index]; } var funcReturn = definition.Body.Accept(this); InstructionBuilder.Return(funcReturn); function.Verify( ); FunctionPassManager.Run(function); return(function); } } catch (CodeGeneratorException) { function.EraseFromParent( ); throw; } }
private void EmitBranchToNewBlock(string blockName) { var newBlock = InstructionBuilder.InsertFunction?.AppendBasicBlock(blockName) ?? throw new InternalCodeGeneratorException("ICE: Expected an insertion block attached to a function at this point"); InstructionBuilder.Branch(newBlock); InstructionBuilder.PositionAtEnd(newBlock); }
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")); }
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); }
public override Value?Visit(FunctionDefinition definition) { definition.ValidateNotNull(nameof(definition)); var function = GetOrDeclareFunction(definition.Signature); if (!function.IsDeclaration) { throw new CodeGeneratorException($"Function {function.Name} cannot be redefined in the same module"); } try { var entryBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(entryBlock); using (NamedValues.EnterScope( )) { foreach (var param in definition.Signature.Parameters) { var argSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(param.Name); InstructionBuilder.Store(function.Parameters[param.Index], argSlot); NamedValues[param.Name] = argSlot; } foreach (LocalVariableDeclaration local in definition.LocalVariables) { var localSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(local.Name); NamedValues[local.Name] = localSlot; } EmitBranchToNewBlock("body"); var funcReturn = definition.Body.Accept(this) ?? throw new CodeGeneratorException(ExpectValidFunc); InstructionBuilder.Return(funcReturn); function.Verify( ); FunctionPassManager.Run(function); if (definition.IsAnonymous) { function.AddAttribute(FunctionAttributeIndex.Function, AttributeKind.AlwaysInline) .Linkage(Linkage.Private); AnonymousFunctions.Add(function); } return(function); } } catch (CodeGeneratorException) { function.EraseFromParent( ); throw; } }
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); }
private (Function Function, int JitHandle) DefineFunction(Function function, ExpressionContext body) { if (!function.IsDeclaration) { throw new ArgumentException($"Function {function.Name} cannot be redefined", nameof(function)); } var basicBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(basicBlock); NamedValues.Clear( ); foreach (var arg in function.Parameters) { var argSlot = CreateEntryBlockAlloca(function, arg.Name); InstructionBuilder.Store(arg, argSlot); NamedValues[arg.Name] = argSlot; } var funcReturn = body.Accept(this); if (funcReturn == null) { function.EraseFromParent( ); return(null, default);
/* * // 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( )); }
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( )); } }
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")); }
public override Value?Visit(FunctionDefinition definition) { definition.ValidateNotNull(nameof(definition)); var function = GetOrDeclareFunction(definition.Signature); if (!function.IsDeclaration) { throw new CodeGeneratorException($"Function {function.Name} cannot be redefined in the same module"); } Debug.Assert(function.DISubProgram != null, "Expected function with non-null DISubProgram"); LexicalBlocks.Push(function.DISubProgram); try { var entryBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(entryBlock); // Unset the location for the prologue emission (leading instructions with no // location in a function are considered part of the prologue and the debugger // will run past them when breaking on a function) EmitLocation(null); using (NamedValues.EnterScope( )) { foreach (var param in definition.Signature.Parameters) { var argSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(param.Name); AddDebugInfoForAlloca(argSlot, function, param); InstructionBuilder.Store(function.Parameters[param.Index], argSlot); NamedValues[param.Name] = argSlot; } foreach (LocalVariableDeclaration local in definition.LocalVariables) { var localSlot = InstructionBuilder.Alloca(function.Context.DoubleType) .RegisterName(local.Name); AddDebugInfoForAlloca(localSlot, function, local); NamedValues[local.Name] = localSlot; } EmitBranchToNewBlock("body"); var funcReturn = definition.Body.Accept(this) ?? throw new CodeGeneratorException(ExpectValidFunc); InstructionBuilder.Return(funcReturn); Module.DIBuilder.Finish(function.DISubProgram); function.Verify( ); FunctionPassManager.Run(function); if (definition.IsAnonymous) { function.AddAttribute(FunctionAttributeIndex.Function, AttributeKind.AlwaysInline) .Linkage(Linkage.Private); AnonymousFunctions.Add(function); } return(function); } } catch (CodeGeneratorException) { function.EraseFromParent( ); throw; } }
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( )); } }
private Function DefineFunction(Function function, ExpressionContext body) { if (!function.IsDeclaration) { throw new ArgumentException($"Function {function.Name} cannot be redefined", nameof(function)); } var proto = FunctionPrototypes[function.Name]; var basicBlock = function.AppendBasicBlock("entry"); InstructionBuilder.PositionAtEnd(basicBlock); var diFile = Module.DICompileUnit.File; var scope = Module.DICompileUnit; LexicalBlocks.Push(function.DISubProgram); // Unset the location for the prologue emission (leading instructions with no // location in a function are considered part of the prologue and the debugger // will run past them when breaking on a function) EmitLocation(null); NamedValues.Clear( ); foreach (var arg in function.Parameters) { uint line = ( uint )proto.Parameters[( int )(arg.Index)].Span.StartLine; uint col = ( uint )proto.Parameters[( int )(arg.Index)].Span.StartColumn; var argSlot = CreateEntryBlockAlloca(function, arg.Name); DILocalVariable debugVar = Module.DIBuilder.CreateArgument(function.DISubProgram , arg.Name , diFile , line , DoubleType , true , DebugInfoFlags.None , checked (( ushort )(arg.Index + 1)) // Debug index starts at 1! ); Module.DIBuilder.InsertDeclare(argSlot , debugVar , new DILocation(Context, line, col, function.DISubProgram) , InstructionBuilder.InsertBlock ); InstructionBuilder.Store(arg, argSlot); NamedValues[arg.Name] = argSlot; } var funcReturn = body.Accept(this); if (funcReturn == null) { function.EraseFromParent( ); LexicalBlocks.Pop( ); return(null); } InstructionBuilder.Return(funcReturn); LexicalBlocks.Pop( ); Module.DIBuilder.Finish(function.DISubProgram); function.Verify( ); Trace.TraceInformation(function.ToString( )); return(function); }