From 93327fd3dcc20b6276e5c5ab7174f4047610ffad Mon Sep 17 00:00:00 2001 From: OnlyYu1996 <1158673577@qq.com> Date: Sun, 17 May 2026 04:24:02 +0800 Subject: [PATCH] Fix inline assignment local declarations --- .../aparapi/internal/writer/BlockWriter.java | 178 ++++++++++++++++-- .../test/AssignAndPassAsParameterSimple.java | 24 ++- .../AssignAndPassAsParameterSimpleTest.java | 29 ++- .../codegen/test/FirstAssignInExpression.java | 7 +- .../test/FirstAssignInExpression2.java | 13 +- .../test/FirstAssignInExpression2Test.java | 16 +- .../test/FirstAssignInExpressionTest.java | 29 ++- 7 files changed, 255 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/aparapi/internal/writer/BlockWriter.java b/src/main/java/com/aparapi/internal/writer/BlockWriter.java index 013239d0..e21fddcd 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 Stack> hoistedLocalDeclarations = new Stack>(); + public abstract void write(String _string); public void writeln(String _string) { @@ -320,6 +322,7 @@ protected void writeGetterBlock(FieldEntry accessorVariableFieldEntry) { public void writeBlock(Instruction _first, Instruction _last) throws CodeGenException { write("{"); in(); + writeHoistedLocalDeclarations(_first, _last); writeSequence(_first, _last); out(); newLine(); @@ -327,6 +330,153 @@ public void writeBlock(Instruction _first, Instruction _last) throws CodeGenExce write("}"); } + private void writeHoistedLocalDeclarations(Instruction _first, Instruction _last) { + final LinkedHashMap declarations = new LinkedHashMap(); + final int blockEndPc = _last == null ? Integer.MAX_VALUE : _last.getThisPC(); + + for (Instruction instruction = _first; instruction != _last; instruction = instruction.getNextExpr()) { + collectHoistedLocalDeclarations(instruction, blockEndPc, declarations); + } + + for (final LocalVariableInfo localVariableInfo : declarations.values()) { + final String key = localVariableDeclarationKey(localVariableInfo); + if (!getHoistedLocalDeclarations().contains(key)) { + getHoistedLocalDeclarations().add(key); + newLine(); + writeLocalDeclaration(localVariableInfo, true); + write(";"); + } + } + } + + private void collectHoistedLocalDeclarations(Instruction instruction, int blockEndPc, + Map declarations) { + if (instruction instanceof CompositeInstruction) { + if (skipCompositeHoistingScan(instruction)) { + return; + } + final int compositeEndPc = instruction.getThisPC(); + collectEscapingHoistedLocalDeclarations(instruction.getFirstChild(), null, compositeEndPc, blockEndPc, declarations); + } else { + collectHoistedLocalDeclarationsInExpression(instruction, blockEndPc, declarations, false); + } + } + + private void collectEscapingHoistedLocalDeclarations(Instruction first, Instruction last, int nestedBlockEndPc, int blockEndPc, + Map declarations) { + for (Instruction instruction = first; instruction != last; instruction = instruction.getNextExpr()) { + if (instruction instanceof CompositeInstruction) { + if (!skipCompositeHoistingScan(instruction)) { + collectEscapingHoistedLocalDeclarations(instruction.getFirstChild(), null, nestedBlockEndPc, blockEndPc, declarations); + } + } else { + collectHoistedLocalDeclarationsInExpression(instruction, blockEndPc, declarations, nestedBlockEndPc, true); + } + } + } + + private boolean skipCompositeHoistingScan(Instruction instruction) { + return instruction instanceof CompositeForSunInstruction || instruction instanceof CompositeForEclipseInstruction + || instruction instanceof CompositeEmptyLoopInstruction || instruction instanceof CompositeArbitraryScopeInstruction; + } + + private void collectHoistedLocalDeclarationsInExpression(Instruction instruction, int blockEndPc, + Map declarations, boolean includeRootAssignment) { + collectHoistedLocalDeclarationsInExpression(instruction, blockEndPc, declarations, -1, includeRootAssignment); + } + + private void collectHoistedLocalDeclarationsInExpression(Instruction instruction, int blockEndPc, + Map declarations, int mustEscapePc, boolean includeRootAssignment) { + if (instruction == null) { + return; + } + + if (includeRootAssignment && instruction instanceof AssignToLocalVariable) { + collectHoistedLocalDeclaration((AssignToLocalVariable) instruction, blockEndPc, declarations, mustEscapePc); + } + + if (instruction.getByteCode().equals(ByteCode.INLINE_ASSIGN)) { + final InlineAssignInstruction inlineAssignInstruction = (InlineAssignInstruction) instruction; + collectHoistedLocalDeclaration(inlineAssignInstruction.getAssignToLocalVariable(), blockEndPc, declarations, mustEscapePc); + } else 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) { + collectHoistedLocalDeclaration(from, blockEndPc, declarations, mustEscapePc); + from = (AssignToLocalVariable) ((Instruction) from).getNextExpr(); + } + collectHoistedLocalDeclarationsInExpression(multiAssignInstruction.getCommon(), blockEndPc, declarations, mustEscapePc, true); + } + + for (Instruction child = instruction.getFirstChild(); child != null; child = child.getNextExpr()) { + collectHoistedLocalDeclarationsInExpression(child, blockEndPc, declarations, mustEscapePc, true); + } + } + + private void collectHoistedLocalDeclaration(AssignToLocalVariable assignToLocalVariable, int blockEndPc, + Map declarations, int mustEscapePc) { + if (!assignToLocalVariable.isDeclaration()) { + return; + } + + final LocalVariableInfo localVariableInfo = assignToLocalVariable.getLocalVariableInfo(); + if (localVariableInfo == null) { + return; + } + + if ((mustEscapePc >= 0) && (localVariableInfo.getEnd() <= mustEscapePc)) { + return; + } + + if (localVariableInfo.getEnd() <= blockEndPc) { + declarations.put(localVariableDeclarationKey(localVariableInfo), localVariableInfo); + } + } + + private void writeLocalDeclaration(LocalVariableInfo localVariableInfo, boolean initialize) { + writeLocalType(localVariableInfo); + write(localVariableInfo.getVariableName()); + if (initialize) { + write(" = "); + write(defaultValueForLocalVariable(localVariableInfo)); + } + } + + private void writeLocalType(LocalVariableInfo localVariableInfo) { + final String descriptor = localVariableInfo.getVariableDescriptor(); + if (descriptor.startsWith("[")) { + write(" __global "); + } + write(convertType(descriptor, true, false)); + } + + private String defaultValueForLocalVariable(LocalVariableInfo localVariableInfo) { + final String descriptor = localVariableInfo.getVariableDescriptor(); + if ("F".equals(descriptor) || "float".equals(descriptor)) { + return "0.0f"; + } else if ("D".equals(descriptor) || "double".equals(descriptor)) { + return "0.0"; + } else if ("J".equals(descriptor) || "long".equals(descriptor)) { + return "0L"; + } else { + return "0"; + } + } + + private Set getHoistedLocalDeclarations() { + return hoistedLocalDeclarations.isEmpty() ? Collections. emptySet() : hoistedLocalDeclarations.peek(); + } + + private boolean isHoistedLocalDeclaration(LocalVariableInfo localVariableInfo) { + return getHoistedLocalDeclarations().contains(localVariableDeclarationKey(localVariableInfo)); + } + + private String localVariableDeclarationKey(LocalVariableInfo localVariableInfo) { + return localVariableInfo.getVariableIndex() + ":" + localVariableInfo.getVariableDescriptor() + ":" + + localVariableInfo.getVariableName(); + } + public Instruction writeConditional(BranchSet _branchSet) throws CodeGenException { return (writeConditional(_branchSet, false)); } @@ -420,16 +570,11 @@ public void writeInstruction(Instruction _instruction) throws CodeGenException { write(localVariableInfo.getVariableName()); } } else { - if (assignToLocalVariable.isDeclaration()) { - final String descriptor = localVariableInfo.getVariableDescriptor(); - // Arrays always map to __global arrays - if (descriptor.startsWith("[")) { - write(" __global "); - } - write(convertType(descriptor, true, false)); - } if (localVariableInfo == null) { throw new CodeGenException("outOfScope" + _instruction.getThisPC() + " = "); + } else if (assignToLocalVariable.isDeclaration() && !isHoistedLocalDeclaration(localVariableInfo)) { + writeLocalType(localVariableInfo); + write(localVariableInfo.getVariableName() + " = "); } else { write(localVariableInfo.getVariableName() + " = "); } @@ -682,11 +827,11 @@ 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 if (alv.isDeclaration() && !isHoistedLocalDeclaration(localVariableInfo)) { + writeLocalType(localVariableInfo); + write(localVariableInfo.getVariableName() + " = "); } else { write(localVariableInfo.getVariableName() + " = "); } @@ -698,7 +843,9 @@ public void writeInstruction(Instruction _instruction) throws CodeGenException { final AssignToLocalVariable assignToLocalVariable = inlineAssignInstruction.getAssignToLocalVariable(); final LocalVariableInfo localVariableInfo = assignToLocalVariable.getLocalVariableInfo(); - if (assignToLocalVariable.isDeclaration()) { + if (localVariableInfo == null) { + throw new CodeGenException("outOfScope" + _instruction.getThisPC() + " = "); + } else if (assignToLocalVariable.isDeclaration() && !isHoistedLocalDeclaration(localVariableInfo)) { // 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 */"); @@ -870,7 +1017,12 @@ public void writeMethodBody(MethodModel _methodModel) throws CodeGenException { FieldEntry accessorVariableFieldEntry = _methodModel.getAccessorVariableFieldEntry(); writeGetterBlock(accessorVariableFieldEntry); } else { - writeBlock(_methodModel.getExprHead(), null); + hoistedLocalDeclarations.push(new HashSet()); + try { + writeBlock(_methodModel.getExprHead(), null); + } finally { + hoistedLocalDeclarations.pop(); + } } } diff --git a/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimple.java b/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimple.java index 8c62403e..465dfc5f 100644 --- a/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimple.java +++ b/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimple.java @@ -26,4 +26,26 @@ public void run() { actuallyDoIt(z = 1); } } -/**{Throws{CodeGenException}Throws}**/ +/**{OpenCL{ + typedef struct This_s{ + int passid; + }This; + int get_pass_id(This *this){ + return this->passid; + } + void com_aparapi_codegen_test_AssignAndPassAsParameterSimple__actuallyDoIt(This *this, int a){ + return; + } + __kernel void run( + int passid + ){ + This thisStruct; + This* this=&thisStruct; + this->passid = passid; + { + int z = 0; + com_aparapi_codegen_test_AssignAndPassAsParameterSimple__actuallyDoIt(this, z=1); + return; + } + } + }OpenCL}**/ diff --git a/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimpleTest.java b/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimpleTest.java index efff6cd5..f9cd6ea8 100644 --- a/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimpleTest.java +++ b/src/test/java/com/aparapi/codegen/test/AssignAndPassAsParameterSimpleTest.java @@ -15,15 +15,34 @@ */ package com.aparapi.codegen.test; -import com.aparapi.internal.exception.ClassParseException; -import com.aparapi.internal.exception.CodeGenException; -import org.junit.Ignore; import org.junit.Test; public class AssignAndPassAsParameterSimpleTest extends com.aparapi.codegen.CodeGenJUnitBase { - private static final String[] expectedOpenCL = null; - private static final Class expectedException = CodeGenException.class; + private static final String[] expectedOpenCL = { + "typedef struct This_s{\n" + + " int passid;\n" + + " }This;\n" + + " int get_pass_id(This *this){\n" + + " return this->passid;\n" + + " }\n" + + " void com_aparapi_codegen_test_AssignAndPassAsParameterSimple__actuallyDoIt(This *this, int a){\n" + + " return;\n" + + " }\n" + + " __kernel void run(\n" + + " int passid\n" + + " ){\n" + + " This thisStruct;\n" + + " This* this=&thisStruct;\n" + + " this->passid = passid;\n" + + " {\n" + + " int z = 0;\n" + + " com_aparapi_codegen_test_AssignAndPassAsParameterSimple__actuallyDoIt(this, z=1);\n" + + " return;\n" + + " }\n" + + " }\n" + + " "}; + private static final Class expectedException = null; @Test public void AssignAndPassAsParameterSimpleTest() { diff --git a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression.java b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression.java index c3385c93..47712471 100644 --- a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression.java +++ b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression.java @@ -39,7 +39,7 @@ int get_pass_id(This *this){ return this->passid; } - void func(This *this, int _arg){ + void com_aparapi_codegen_test_FirstAssignInExpression__func(This *this, int _arg){ return; } __kernel void run( @@ -49,8 +49,9 @@ __kernel void run( This* this=&thisStruct; this->passid = passid; { - int result; - func(this, result = 0); + int result = 0; + int value = 1; + com_aparapi_codegen_test_FirstAssignInExpression__func(this, result=value); return; } } diff --git a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2.java b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2.java index 3429c586..bb86bcb1 100644 --- a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2.java +++ b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2.java @@ -47,16 +47,17 @@ __kernel void run( This* this=&thisStruct; this->passid = passid; { + int assignMe = 0; int value = 1; - int result=0; - int assignMe=0; - if (true){ + int result = 0; + if (value==value){ result = assignMe = value; - }else{ - assignMe =1; - result=2; + } else { + assignMe = 1; + result = 2; } result++; + assignMe++; return; } } diff --git a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java index 186927cc..ecfa6092 100644 --- a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java +++ b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpression2Test.java @@ -15,7 +15,6 @@ */ package com.aparapi.codegen.test; -import org.junit.Ignore; import org.junit.Test; public class FirstAssignInExpression2Test extends com.aparapi.codegen.CodeGenJUnitBase { @@ -35,29 +34,28 @@ public class FirstAssignInExpression2Test extends com.aparapi.codegen.CodeGenJUn + " This* this=&thisStruct;\n" + " this->passid = passid;\n" + " {\n" + + " int assignMe = 0;\n" + " int value = 1;\n" - + " int result=0;\n" - + " int assignMe=0;\n" - + " if (true){\n" + + " int result = 0;\n" + + " if (value==value){\n" + " result = assignMe = value;\n" - + " }else{\n" - + " assignMe =1;\n" - + " result=2;\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); diff --git a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpressionTest.java b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpressionTest.java index ecc5b660..cca53ed2 100644 --- a/src/test/java/com/aparapi/codegen/test/FirstAssignInExpressionTest.java +++ b/src/test/java/com/aparapi/codegen/test/FirstAssignInExpressionTest.java @@ -15,13 +15,34 @@ */ package com.aparapi.codegen.test; -import com.aparapi.internal.exception.CodeGenException; -import org.junit.Ignore; import org.junit.Test; public class FirstAssignInExpressionTest extends com.aparapi.codegen.CodeGenJUnitBase { - private static final String[] expectedOpenCL = null; - private static final Class expectedException = CodeGenException.class; + private static final String[] expectedOpenCL = { + "typedef struct This_s{\n" + + " int passid;\n" + + " }This;\n" + + " int get_pass_id(This *this){\n" + + " return this->passid;\n" + + " }\n" + + " void com_aparapi_codegen_test_FirstAssignInExpression__func(This *this, int _arg){\n" + + " return;\n" + + " }\n" + + " __kernel void run(\n" + + " int passid\n" + + " ){\n" + + " This thisStruct;\n" + + " This* this=&thisStruct;\n" + + " this->passid = passid;\n" + + " {\n" + + " int result = 0;\n" + + " int value = 1;\n" + + " com_aparapi_codegen_test_FirstAssignInExpression__func(this, result=value);\n" + + " return;\n" + + " }\n" + + " }\n" + + " "}; + private static final Class expectedException = null; @Test public void FirstAssignInExpressionTest() {