diff --git a/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.Emitter.cs b/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.Emitter.cs index 5fa76fb1a2..84556d963c 100644 --- a/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.Emitter.cs +++ b/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.Emitter.cs @@ -47,6 +47,7 @@ public struct StatementEmitter : IDisposable #region Instance private readonly StringBuilder stringBuilder; + private readonly StringBuilder variableBuilder; private bool argMode; private int argumentCount; @@ -58,6 +59,7 @@ internal StatementEmitter(CLCodeGenerator codeGenerator) { CodeGenerator = codeGenerator; stringBuilder = codeGenerator.Builder; + variableBuilder = codeGenerator.VariableBuilder; argumentCount = 0; argMode = false; @@ -85,11 +87,7 @@ internal StatementEmitter(CLCodeGenerator codeGenerator) private void BeginAppendTarget(Variable target, bool appendNew = true) { if (appendNew) - { - var variableType = CodeGenerator.GetVariableType(target); - stringBuilder.Append(variableType); - stringBuilder.Append(' '); - } + AppendDeclaration(target); stringBuilder.Append(target.ToString()); } @@ -97,8 +95,15 @@ private void BeginAppendTarget(Variable target, bool appendNew = true) /// Appends a target declaration. /// /// The target declaration. - internal void AppendDeclaration(Variable target) => - BeginAppendTarget(target); + internal void AppendDeclaration(Variable target) + { + var variableType = CodeGenerator.GetVariableType(target); + variableBuilder.Append('\t'); + variableBuilder.Append(variableType); + variableBuilder.Append(' '); + variableBuilder.Append(target.ToString()); + variableBuilder.AppendLine(";"); + } /// /// Appends a target. @@ -828,6 +833,50 @@ public StatementEmitter BeginStatement(FormattableString command) return emitter; } + /// + /// Begins the function body, switching to variable capturing mode. + /// + protected void BeginFunctionBody() + { + // Start the function body. + Builder.AppendLine("{"); + PushIndent(); + +#if DEBUG + Builder.AppendLine(); + Builder.AppendLine("\t// Variable declarations"); + Builder.AppendLine(); +#endif + + // Switch to the alternate builder, so that we can capture the code and + // variable declarations separately. + prefixBuilder = Builder; + Builder = suffixBuilder; + } + + /// + /// Finishes the function body, ending variable capturing mode. + /// + protected void FinishFunctionBody() + { + // Restore the original builder, containing code before the variable + // declarations. + Builder = prefixBuilder; + + // Add the variable declarations at the start of the function, to avoid + // issues with OpenCL compilers that are not C99 compliant, and cannot + // handle variable declarations intermingled with other code. + Builder.Append(VariableBuilder); + Builder.AppendLine(); + + // Add the code that was generated along with the variable declarations. + Builder.Append(suffixBuilder); + + // Close the function body. + PopIndent(); + Builder.AppendLine("}"); + } + #endregion } } diff --git a/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.cs b/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.cs index 6c8273db85..14d8d987bf 100644 --- a/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.cs +++ b/Src/ILGPU/Backends/OpenCL/CLCodeGenerator.cs @@ -279,6 +279,9 @@ protected static string GetParameterName(Parameter parameter) => new Dictionary(); private readonly string labelPrefix; + private StringBuilder prefixBuilder = new StringBuilder(); + private StringBuilder suffixBuilder = new StringBuilder(); + /// /// Constructs a new code generator. /// @@ -295,7 +298,7 @@ internal CLCodeGenerator(in GeneratorArgs args, Method method, Allocas allocas) labelPrefix = "L_" + Method.Id.ToString(); - Builder = new StringBuilder(); + Builder = prefixBuilder; } #endregion @@ -327,7 +330,12 @@ public IntrinsicImplementationProvider /// /// Returns the associated string builder. /// - public StringBuilder Builder { get; } + public StringBuilder Builder { get; private set; } + + /// + /// Returns the associated string builder. + /// + public StringBuilder VariableBuilder { get; } = new StringBuilder(); #endregion diff --git a/Src/ILGPU/Backends/OpenCL/CLFunctionGenerator.cs b/Src/ILGPU/Backends/OpenCL/CLFunctionGenerator.cs index 9b46a7d115..3bb044f938 100644 --- a/Src/ILGPU/Backends/OpenCL/CLFunctionGenerator.cs +++ b/Src/ILGPU/Backends/OpenCL/CLFunctionGenerator.cs @@ -132,11 +132,9 @@ public override void GenerateCode() BindSharedMemoryAllocation(Allocas.DynamicSharedAllocations); // Generate code - Builder.AppendLine("{"); - PushIndent(); + BeginFunctionBody(); GenerateCodeInternal(); - PopIndent(); - Builder.AppendLine("}"); + FinishFunctionBody(); } #endregion diff --git a/Src/ILGPU/Backends/OpenCL/CLKernelFunctionGenerator.cs b/Src/ILGPU/Backends/OpenCL/CLKernelFunctionGenerator.cs index 7257df58d2..95d0ab5a4b 100644 --- a/Src/ILGPU/Backends/OpenCL/CLKernelFunctionGenerator.cs +++ b/Src/ILGPU/Backends/OpenCL/CLKernelFunctionGenerator.cs @@ -262,8 +262,7 @@ public override void GenerateCode() Builder.AppendLine(")"); // Emit code that moves view arguments into their appropriate targets - Builder.AppendLine("{"); - PushIndent(); + BeginFunctionBody(); GenerateArgumentMapping(); // Emit index computation @@ -323,8 +322,7 @@ public override void GenerateCode() // Generate code GenerateCodeInternal(); - PopIndent(); - Builder.AppendLine("}"); + FinishFunctionBody(); } ///