diff --git a/src/main/java/com/aparapi/internal/writer/BlockWriter.java b/src/main/java/com/aparapi/internal/writer/BlockWriter.java index 013239d0..25f2d5dd 100644 --- a/src/main/java/com/aparapi/internal/writer/BlockWriter.java +++ b/src/main/java/com/aparapi/internal/writer/BlockWriter.java @@ -80,6 +80,8 @@ public abstract class BlockWriter{ public final static String arrayDimMangleSuffix = "__javaArrayDimension"; + private final Set declaredExpressionLocals = new HashSet(); + public abstract void write(String _string); public void writeln(String _string) { @@ -304,6 +306,63 @@ public void writeSequence(Instruction _first, Instruction _last) throws CodeGenE } + private void collectExpressionDeclarations(Instruction _instruction, Set _locals) { + if (_instruction == null) { + return; + } + + if (_instruction.getByteCode().equals(ByteCode.MULTI_ASSIGN)) { + final MultiAssignInstruction multiAssignInstruction = (MultiAssignInstruction) _instruction; + AssignToLocalVariable from = (AssignToLocalVariable) multiAssignInstruction.getFrom(); + final AssignToLocalVariable last = (AssignToLocalVariable) multiAssignInstruction.getTo(); + + while (from != last) { + addExpressionDeclaration(from, _locals); + from = (AssignToLocalVariable) ((Instruction) from).getNextExpr(); + } + } else if (_instruction.getByteCode().equals(ByteCode.INLINE_ASSIGN)) { + final InlineAssignInstruction inlineAssignInstruction = (InlineAssignInstruction) _instruction; + addExpressionDeclaration(inlineAssignInstruction.getAssignToLocalVariable(), _locals); + } + + for (Instruction child = _instruction.getFirstChild(); child != null; child = child.getNextExpr()) { + collectExpressionDeclarations(child, _locals); + } + } + + private void addExpressionDeclaration(AssignToLocalVariable _assignToLocalVariable, Set _locals) { + final LocalVariableInfo localVariableInfo = _assignToLocalVariable.getLocalVariableInfo(); + if (_assignToLocalVariable.isDeclaration() && localVariableInfo != null + && !declaredExpressionLocals.contains(getLocalVariableKey(localVariableInfo))) { + _locals.add(localVariableInfo); + } + } + + private String getLocalVariableKey(LocalVariableInfo _localVariableInfo) { + return _localVariableInfo.getVariableIndex() + ":" + _localVariableInfo.getVariableName(); + } + + private boolean hasExpressionDeclaration(LocalVariableInfo _localVariableInfo) { + return declaredExpressionLocals.contains(getLocalVariableKey(_localVariableInfo)); + } + + private void writeExpressionDeclarations(Instruction _first, Instruction _last) throws CodeGenException { + final Set locals = new LinkedHashSet(); + for (Instruction instruction = _first; instruction != _last; instruction = instruction.getNextExpr()) { + collectExpressionDeclarations(instruction, locals); + } + + for (LocalVariableInfo localVariableInfo : locals) { + final String localVariableKey = getLocalVariableKey(localVariableInfo); + if (!declaredExpressionLocals.contains(localVariableKey)) { + newLine(); + write(convertType(localVariableInfo.getVariableDescriptor(), true, false)); + write(localVariableInfo.getVariableName() + "=0;"); + declaredExpressionLocals.add(localVariableKey); + } + } + } + protected void writeGetterBlock(FieldEntry accessorVariableFieldEntry) { write("{"); in(); @@ -320,6 +379,7 @@ protected void writeGetterBlock(FieldEntry accessorVariableFieldEntry) { public void writeBlock(Instruction _first, Instruction _last) throws CodeGenException { write("{"); in(); + writeExpressionDeclarations(_first, _last); writeSequence(_first, _last); out(); newLine(); @@ -420,7 +480,7 @@ public void writeInstruction(Instruction _instruction) throws CodeGenException { write(localVariableInfo.getVariableName()); } } else { - if (assignToLocalVariable.isDeclaration()) { + if (assignToLocalVariable.isDeclaration() && !hasExpressionDeclaration(localVariableInfo)) { final String descriptor = localVariableInfo.getVariableDescriptor(); // Arrays always map to __global arrays if (descriptor.startsWith("[")) { @@ -682,9 +742,6 @@ public void writeInstruction(Instruction _instruction) throws CodeGenException { for (AssignToLocalVariable alv = stack.pop(); alv != null; alv = stack.size() > 0 ? stack.pop() : null) { final LocalVariableInfo localVariableInfo = alv.getLocalVariableInfo(); - if (alv.isDeclaration()) { - write(convertType(localVariableInfo.getVariableDescriptor(), true, false)); - } if (localVariableInfo == null) { throw new CodeGenException("outOfScope" + _instruction.getThisPC() + " = "); } else { @@ -698,11 +755,6 @@ public void writeInstruction(Instruction _instruction) throws CodeGenException { final AssignToLocalVariable assignToLocalVariable = inlineAssignInstruction.getAssignToLocalVariable(); final LocalVariableInfo localVariableInfo = assignToLocalVariable.getLocalVariableInfo(); - if (assignToLocalVariable.isDeclaration()) { - // this is bad! we need a general way to hoist up a required declaration - throw new CodeGenException("/* we can't declare this " + convertType(localVariableInfo.getVariableDescriptor(), true, false) - + " here */"); - } write(localVariableInfo.getVariableName()); write("="); writeInstruction(inlineAssignInstruction.getRhs()); @@ -866,6 +918,7 @@ public void writeThisRef() { } public void writeMethodBody(MethodModel _methodModel) throws CodeGenException { + declaredExpressionLocals.clear(); if (_methodModel.isGetter() && !_methodModel.isNoCL()) { FieldEntry accessorVariableFieldEntry = _methodModel.getAccessorVariableFieldEntry(); writeGetterBlock(accessorVariableFieldEntry); diff --git a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java index 186927cc..0e735ad8 100644 --- a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java +++ b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java @@ -15,49 +15,45 @@ */ package com.aparapi.codegen.test; -import org.junit.Ignore; import org.junit.Test; public class FirstAssignInExpression2Test extends com.aparapi.codegen.CodeGenJUnitBase { private static final String[] expectedOpenCL = { "typedef struct This_s{\n" - + "\n" - + " int passid;\n" - + " }This;\n" - + " int get_pass_id(This *this){\n" - + " return this->passid;\n" - + " }\n" - + " __kernel void run(\n" - + " int passid\n" - + " ){\n" - + " This thisStruct;\n" - + " This* this=&thisStruct;\n" - + " this->passid = passid;\n" - + " {\n" - + " int value = 1;\n" - + " int result=0;\n" - + " int assignMe=0;\n" - + " if (true){\n" - + " result = assignMe = value;\n" - + " }else{\n" - + " assignMe =1;\n" - + " result=2;\n" - + " }\n" - + " result++;\n" - + " return;\n" - + " }\n" - + " }\n" - + " "}; + + " int passid;\n" + + "}This;\n" + + "int get_pass_id(This *this){\n" + + " return this->passid;\n" + + "}\n" + + "__kernel void run(\n" + + " int passid\n" + + "){\n" + + " This thisStruct;\n" + + " This* this=&thisStruct;\n" + + " this->passid = passid;\n" + + " {\n" + + " int assignMe=0;\n" + + " int value = 1;\n" + + " int result = 0;\n" + + " if (value==value){\n" + + " result = assignMe = value;\n" + + " } else {\n" + + " assignMe = 1;\n" + + " result = 2;\n" + + " }\n" + + " result++;\n" + + " assignMe++;\n" + + " return;\n" + + " }\n" + + "}\n"}; private static final Class expectedException = null; - @Ignore @Test public void FirstAssignInExpression2Test() { test(com.aparapi.codegen.test.FirstAssignInExpression2.class, expectedException, expectedOpenCL); } - @Ignore @Test public void FirstAssignInExpression2TestWorksWithCaching() { test(com.aparapi.codegen.test.FirstAssignInExpression2.class, expectedException, expectedOpenCL);