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();
}
///