Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Changing C# codegen to happen synch. #631

Merged
merged 4 commits into from
Mar 26, 2022
Merged
Changes from 1 commit
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
77 changes: 37 additions & 40 deletions src/Core/Compiler/CompilerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,49 +382,12 @@ string WrapInNamespace(Snippet s) =>
try
{
using var codeGenTask = perfTask?.BeginSubtask("Code generation", "code-generation");
// Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees:
var trees = new List<Task<CodeAnalysis.SyntaxTree>>();
var allSources = regenerateAll
? GetSourceFiles.Apply(qsCompilation.Namespaces)
: sources.Keys.Select(
file => CompilationUnitManager.GetFileId(file)
);

foreach (var file in allSources)
{
trees.Add(Task.Run(() =>
{
codeGenTask?.ReportStatus($"Creating codegen context for file {file}", "generate-one-file");
var codegenContext = string.IsNullOrEmpty(executionTarget)
? CodegenContext.Create(qsCompilation.Namespaces)
: CodegenContext.Create(qsCompilation.Namespaces, new Dictionary<string, string>() { { AssemblyConstants.ExecutionTarget, executionTarget } });
codeGenTask?.ReportStatus($"Generating C# for file {file}", "generate-one-file");
var code = SimulationCode.generate(file, codegenContext);
codeGenTask?.ReportStatus($"Parsing generated C# for file {file}", "generate-one-file");
logger.LogDebug($"Generated the following C# code for {file}:\n=============\n{code}\n=============\n");
return CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8);
}));
}

// Compile the C# syntax trees:
var compilation = Task.Run(async () =>
{
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug);
var parsedTrees = await Task.WhenAll(trees);
using var csCompileTask = codeGenTask?.BeginSubtask("Compiling generated C#.", "compile-csharp");

return CSharpCompilation.Create(
Path.GetFileNameWithoutExtension(dllName),
parsedTrees,
metadata.RoslynMetadatas,
options);
});

var fromSources = regenerateAll
? qsCompilation.Namespaces
: qsCompilation.Namespaces.Select(ns => FilterBySourceFile.Apply(ns, s => s.EndsWith(".qs")));

// In parallel, get manifest resources by writing syntax trees to memory.
// Async, get manifest resources by writing syntax trees to memory.
var manifestResources = Task.Run(() =>
{
using var qstTask = codeGenTask?.BeginSubtask("Serializing Q# syntax tree.", "serialize-qs-ast");
Expand All @@ -447,10 +410,44 @@ string WrapInNamespace(Snippet s) =>
};
});

// Generate the assembly from the C# compilation once we have
// In the meanwhile...
// Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees:
var allSources = regenerateAll
? GetSourceFiles.Apply(qsCompilation.Namespaces)
: sources.Keys.Select(
file => CompilationUnitManager.GetFileId(file)
);

CodeAnalysis.SyntaxTree createTree(string file)
{
codeGenTask?.ReportStatus($"Creating codegen context for file {file}", "generate-one-file");
var codegenContext = string.IsNullOrEmpty(executionTarget)
? CodegenContext.Create(qsCompilation.Namespaces)
: CodegenContext.Create(qsCompilation.Namespaces, new Dictionary<string, string>() { { AssemblyConstants.ExecutionTarget, executionTarget } });
codeGenTask?.ReportStatus($"Generating C# for file {file}", "generate-one-file");
var code = SimulationCode.generate(file, codegenContext);
var filename = Path.Combine(".", "obj", new FileInfo(file).Name + ".cs");
File.WriteAllText(filename, code);
codeGenTask?.ReportStatus($"Parsing generated C# for file {file}", "generate-one-file");
logger.LogDebug($"Generated the following C# code for {file}:\n=============\n{code}\n=============\n");
return CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8);
}

var trees = allSources.Select(createTree).ToImmutableList();
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug);
var parsedTrees = trees;
using var csCompileTask = codeGenTask?.BeginSubtask("Compiling generated C#.", "compile-csharp");

var compilation = CSharpCompilation.Create(
Path.GetFileNameWithoutExtension(dllName),
parsedTrees,
metadata.RoslynMetadatas,
options);

// Generate the assembly from the C# compilation and the manifestResources once we have
// both.
using var ms = new MemoryStream();
var result = (await compilation).Emit(ms, manifestResources: await manifestResources);
var result = compilation.Emit(ms, manifestResources: await manifestResources);

if (!result.Success)
{
Expand Down