Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 33 additions & 24 deletions Samples/Kaleidoscope/Chapter6/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,19 @@ internal sealed class CodeGenerator
, IDisposable
, IKaleidoscopeCodeGenerator<Value>
{
// <Initialization>
public CodeGenerator( DynamicRuntimeState globalState )
{
RuntimeState = globalState;
Context = new Context( );
JIT = new KaleidoscopeJIT( );
InitializeModuleAndPassManager( );
InstructionBuilder = new InstructionBuilder( Context );
JIT = new KaleidoscopeJIT( );
FunctionPrototypes = new PrototypeCollection( );
FunctionModuleMap = new Dictionary<string, IJitModuleHandle>( );
NamedValues = new ScopeStack<Value>( );
}
// </Initialization>

public bool DisableOptimizations { get; set; }

Expand Down Expand Up @@ -82,7 +84,7 @@ public override Value VisitVariableExpression( [NotNull] VariableExpressionConte

public override Value VisitFunctionCallExpression( [NotNull] FunctionCallExpressionContext context )
{
var function = GetFunction( context.CaleeName );
var function = FindCallTarget( context.CaleeName );
if( function == null )
{
throw new CodeGeneratorException( $"function '{context.CaleeName}' is unknown" );
Expand All @@ -102,13 +104,16 @@ public override Value VisitFunctionPrototype( [NotNull] FunctionPrototypeContext
return GetOrDeclareFunction( new Prototype( context ) );
}

// <VisitFunctionDefinition>
public override Value VisitFunctionDefinition( [NotNull] FunctionDefinitionContext context )
{
return DefineFunction( ( Function )context.Signature.Accept( this )
, context.BodyExpression
).Function;
}
// </VisitFunctionDefinition>

// <VisitTopLevelExpression>
public override Value VisitTopLevelExpression( [NotNull] TopLevelExpressionContext context )
{
var proto = new Prototype( $"anon_expr_{AnonNameIndex++}" );
Expand All @@ -118,9 +123,11 @@ public override Value VisitTopLevelExpression( [NotNull] TopLevelExpressionConte

var nativeFunc = JIT.GetDelegateForFunction<AnonExpressionFunc>( proto.Identifier.Name );
var retVal = Context.CreateConstant( nativeFunc( ) );
FunctionModuleMap.Remove( function.Name );
JIT.RemoveModule( jitHandle );
return retVal;
}
// </VisitTopLevelExpression>

public override Value VisitExpression( [NotNull] ExpressionContext context )
{
Expand All @@ -135,6 +142,7 @@ public override Value VisitExpression( [NotNull] ExpressionContext context )
return lhs;
}

// <VisitConditionalExpression>
public override Value VisitConditionalExpression( [NotNull] ConditionalExpressionContext context )
{
var condition = context.Condition.Accept( this );
Expand Down Expand Up @@ -163,7 +171,7 @@ public override Value VisitConditionalExpression( [NotNull] ConditionalExpressio

InstructionBuilder.Branch( phiMergeBlock );

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

// generate else block
Expand All @@ -188,24 +196,9 @@ public override Value VisitConditionalExpression( [NotNull] ConditionalExpressio
phiNode.AddIncoming( elseValue, elseBlock );
return phiNode;
}
// </VisitConditionalExpression>

/*
// 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:
*/
// <VisitForExpression>
public override Value VisitForExpression( [NotNull] ForExpressionContext context )
{
var function = InstructionBuilder.InsertBlock.ContainingFunction;
Expand Down Expand Up @@ -297,7 +290,9 @@ public override Value VisitForExpression( [NotNull] ForExpressionContext context
return Context.DoubleType.GetNullValue( );
}
}
// </VisitForExpression>

// <VisitUserOperators>
public override Value VisitUnaryOpExpression( [NotNull] UnaryOpExpressionContext context )
{
// verify the operator was previously defined
Expand All @@ -308,7 +303,7 @@ public override Value VisitUnaryOpExpression( [NotNull] UnaryOpExpressionContext
}

string calleeName = UnaryPrototypeContext.GetOperatorFunctionName( context.OpToken );
var function = GetFunction( calleeName );
var function = FindCallTarget( calleeName );
if( function == null )
{
throw new CodeGeneratorException( $"Unknown function reference {calleeName}" );
Expand Down Expand Up @@ -338,6 +333,7 @@ public override Value VisitUnaryPrototype( [NotNull] UnaryPrototypeContext conte

return GetOrDeclareFunction( new Prototype( context, context.Name ) );
}
// </VisitUserOperators>

protected override Value DefaultResult => null;

Expand Down Expand Up @@ -378,6 +374,7 @@ private Value EmitBinaryOperator( Value lhs, BinaryopContext op, IParseTree righ
case SLASH:
return InstructionBuilder.FDiv( lhs, rhs ).RegisterName( "divtmp" );

// <EmitUserOperator>
default:
{
// User defined op?
Expand All @@ -388,30 +385,37 @@ private Value EmitBinaryOperator( Value lhs, BinaryopContext op, IParseTree righ
}

string calleeName = BinaryPrototypeContext.GetOperatorFunctionName( op.Token );
var function = GetFunction( calleeName );
var function = FindCallTarget( calleeName );
if( function == null )
{
throw new CodeGeneratorException( $"Unknown function reference {calleeName}" );
}

return InstructionBuilder.Call( function, lhs, rhs ).RegisterName( "calltmp" );
}
// </EmitUserOperator>
}
}

// <InitializeModuleAndPassManager>
private void InitializeModuleAndPassManager( )
{
Module = Context.CreateBitcodeModule( );
Module.Layout = JIT.TargetMachine.TargetData;
FunctionPassManager = new FunctionPassManager( Module );
FunctionPassManager.AddInstructionCombiningPass( )
.AddReassociatePass( )
.AddGVNPass( )
.AddCFGSimplificationPass( )
.Initialize( );
}
// </InitializeModuleAndPassManager>

private Function GetFunction( string name )
// <FindCallTarget>
private Function FindCallTarget( string name )
{
// lookup the prototype for the function to get the signature
// and create a declaration in this module
if( FunctionPrototypes.TryGetValue( name, out var signature ) )
{
return GetOrDeclareFunction( signature );
Expand All @@ -425,7 +429,9 @@ private Function GetFunction( string name )

return null;
}
// </FindCallTarget>

// <GetOrDeclareFunction>
private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = false )
{
var function = Module.GetFunction( prototype.Identifier.Name );
Expand Down Expand Up @@ -453,7 +459,9 @@ private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = f

return retVal;
}
// </GetOrDeclareFunction>

// <DefineFunction>
private (Function Function, IJitModuleHandle JitHandle) DefineFunction( Function function, ExpressionContext body )
{
if( !function.IsDeclaration )
Expand All @@ -466,7 +474,7 @@ private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = f
// implementation. This is needed, otherwise both the MCJIT
// and OrcJit engines will resolve to the original module, despite
// claims to the contrary in the official tutorial text. (Though,
// to be fare it may have been true in the original JIT and might
// to be fair it may have been true in the original JIT and might
// still be true for the interpreter)
if( FunctionModuleMap.Remove( function.Name, out IJitModuleHandle handle ) )
{
Expand Down Expand Up @@ -503,6 +511,7 @@ private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = f
InitializeModuleAndPassManager( );
return (function, jitHandle);
}
// </DefineFunction>

// <PrivateMembers>
private readonly DynamicRuntimeState RuntimeState;
Expand Down
24 changes: 24 additions & 0 deletions Samples/Kaleidoscope/Chapter6/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

[assembly: SuppressMessage( "StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Sample application" )]

#pragma warning disable SA1512, SA1513, SA1515 // single line comments used to tag regions for extraction into docs

namespace Kaleidoscope
{
public static class Program
Expand All @@ -35,6 +37,8 @@ public static void Main( string[ ] args )
using( InitializeLLVM( ) )
{
RegisterNative( );

// <generatorloop>
var parser = new ReplParserStack( LanguageLevel.UserDefinedOperators );
using( var generator = new CodeGenerator( parser.GlobalState ) )
{
Expand All @@ -43,12 +47,31 @@ public static void Main( string[ ] args )
var replLoop = new ReplLoop<Value>( generator, parser );
replLoop.ReadyStateChanged += ( s, e ) => Console.Write( e.PartialParse ? ">" : "Ready>" );
replLoop.GeneratedResultAvailable += OnGeneratedResultAvailable;
replLoop.CodeGenerationError += OnGeneratorError;

replLoop.Run( );
}
// </generatorloop>
}
}

// <ErrorHandling>
private static void OnGeneratorError( object sender, CodeGenerationExceptionArgs e )
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
try
{
Console.Error.WriteLine( e.Exception.Message );
}
finally
{
Console.ForegroundColor = color;
}
}
// </ErrorHandling>

// <ResultProcessing>
private static void OnGeneratedResultAvailable( object sender, GeneratedResultAvailableArgs<Value> e )
{
var source = ( ReplLoop<Value> )sender;
Expand All @@ -69,5 +92,6 @@ private static void OnGeneratedResultAvailable( object sender, GeneratedResultAv
break;
}
}
// </ResultProcessing>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Kaleidoscope.Grammar
/// The resulting ".diag" file is convertible to SVG form for documentation.</para>
/// <para>
/// The generated diagrams include a numbered element for binary operator expressions
/// to indicate the precedence value that is diyamically evaluated for the expression.
/// to indicate the precedence value that is dynamically evaluated for the expression.
/// This is particularly useful for debugging custom operator precedence problems.
/// </para>
/// </remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ namespace Kaleidoscope.Grammar
///
/// This provides storage and support methods for the runtime global state.
/// In particular, it maintains the language level to use and the current set
/// of operators, including any user defined operators so the parser know how
/// to resolve complex expressions with precednece.
/// of operators, including any user defined operators so the parser knows how
/// to resolve complex expressions with user defined operators and precedence.
/// </remarks>
public class DynamicRuntimeState
{
Expand Down Expand Up @@ -106,7 +106,7 @@ internal int GetNextPrecedence( int tokenType )

private bool TryAddOperator( int tokenType, OperatorKind kind, int precedence )
{
// internally operators are stored as token type integers to accomodate
// internally operators are stored as token type integers to accommodate
// simpler condition checks and switching on operator types in code generation
switch( kind )
{
Expand Down
4 changes: 2 additions & 2 deletions Samples/Kaleidoscope/Kaleidoscope.Parser/Identifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ namespace Kaleidoscope
{
/// <summary>Description of an identifier in Kaleidoscope code generation</summary>
/// <remarks>
/// This is distinct from te parse tree nodes as code generation sometimes needs to
/// synthesize an identifier (i.e. Building function the definition for an anonymous
/// This is distinct from the parse tree nodes as code generation sometimes needs to
/// synthesize an identifier (i.e. Building the function definition for an anonymous
/// top level expression)
/// </remarks>
public struct Identifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Kaleidoscope.Grammar
{
// partial extension to handle creating virtual tokens/Identifiers depending
// on language feaures enabled.
// on language features enabled.
public partial class KaleidoscopeLexer
{
public LanguageLevel LanguageLevel { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public interface IKaleidoscopeParser
/// <remarks>
/// If the parse fails then the resulting tuple is the default value ( in this case, both items <see langword="null"/>
/// Errors from the parse are reported through error listeners provided
/// to the parser. Normally this is done via the contructor of a type
/// to the parser. Normally this is done via the constructor of a type
/// implementing this interface.
/// </remarks>
(IParseTree parseTree, Parser recognizer) Parse( string txt, DiagnosticRepresentations additionalDiagnostics );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static IEnumerable<string> ReadLines( this TextReader reader )
/// <returns>Enumerable set of lines that may be partial statements</returns>
/// <remarks>
/// Each value enumerated includes the full text since the last complete statement.
/// That is the Txt from multiple partial statements will include the text of the
/// That is the text from multiple partial statements will include the text of the
/// preceding partial. Once a complete statement is found the entire string is provided
/// with the IsPartial property set to <see langword="false"/>
/// </remarks>
Expand All @@ -57,7 +57,7 @@ public static IEnumerable<string> ReadLines( this TextReader reader )
/// <returns>Enumerable set of lines that may be partial statements</returns>
/// <remarks>
/// Each value enumerated includes the full text since the last complete statement.
/// That is the Txt from multiple partial statements will include the text of the
/// That is the text from multiple partial statements will include the text of the
/// preceding partial. Once a complete statement is found the entire string is provided
/// with the IsPartial property set to <see langword="false"/>
/// </remarks>
Expand All @@ -66,7 +66,7 @@ public static IEnumerable<string> ReadLines( this TextReader reader )
var bldr = new StringBuilder( );
foreach( string line in lines )
{
var statements = line.Split( ';' );
string[ ] statements = line.Split( ';' );

// if the last line in the group was terminated with a ; the
// the last entry is an empty string, but a single blank line
Expand Down
2 changes: 1 addition & 1 deletion Samples/Kaleidoscope/Kaleidoscope.Runtime/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static void WaitForDebugger( bool condition )
public static string GetSafeFileName( string name )
{
var bldr = new StringBuilder( name.Length );
var invalidChars = Path.GetInvalidFileNameChars( );
char[ ] invalidChars = Path.GetInvalidFileNameChars( );
foreach( char c in name )
{
bldr.Append( invalidChars.Contains( c ) ? '_' : c );
Expand Down
Loading