From 796e622a8395ccebba3d73a63bdada76f12d8e7d Mon Sep 17 00:00:00 2001 From: mirkosertic Date: Fri, 12 Apr 2024 16:31:53 +0200 Subject: [PATCH] More compiler optimizations --- .../optimizer/CopyToRedundantVariable.java | 114 ++ .../core/optimizer/CopyToUnusedPHI.java | 15 + .../core/optimizer/Optimizations.java | 2 + .../optimizer/PHIorVariableIsConstant.java | 2 +- .../bytecoder/core/optimizer/STATS.md | 5 + manual/static/docassets/ir_loopexample.svg | 722 +++++----- .../docassets/ir_loopexample_optimized.svg | 1162 ++++++----------- 7 files changed, 928 insertions(+), 1094 deletions(-) create mode 100644 core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToRedundantVariable.java diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToRedundantVariable.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToRedundantVariable.java new file mode 100644 index 0000000000..9b6dd3899a --- /dev/null +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToRedundantVariable.java @@ -0,0 +1,114 @@ +/* + * Copyright 2024 Mirko Sertic + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.mirkosertic.bytecoder.core.optimizer; + +import de.mirkosertic.bytecoder.core.backend.BackendType; +import de.mirkosertic.bytecoder.core.ir.ControlTokenConsumer; +import de.mirkosertic.bytecoder.core.ir.Copy; +import de.mirkosertic.bytecoder.core.ir.Graph; +import de.mirkosertic.bytecoder.core.ir.Node; +import de.mirkosertic.bytecoder.core.ir.NodeType; +import de.mirkosertic.bytecoder.core.ir.ResolvedMethod; +import de.mirkosertic.bytecoder.core.ir.Variable; +import de.mirkosertic.bytecoder.core.parser.CompileUnit; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Stack; + +public class CopyToRedundantVariable implements Optimizer { + + private List evaluationOrderOf(final Node node) { + final List result = new ArrayList<>(); + + // We do a DFS here + final Set visited = new HashSet<>(); + final Stack workingQueue = new Stack<>(); + + for (int i = node.incomingDataFlows.length - 1; i >= 0; i--) { + workingQueue.push(node.incomingDataFlows[i]); + } + visited.add(node); + + while (!workingQueue.isEmpty()) { + final Node workingItem = workingQueue.pop(); + if (visited.add(workingItem)) { + if (!(workingItem instanceof ControlTokenConsumer)) { + if (workingItem.hasSideSideEffect() || workingItem.nodeType == NodeType.Variable) { + result.add(workingItem); + } else { + for (int i = workingItem.incomingDataFlows.length - 1; i >= 0; i--) { + workingQueue.push(workingItem.incomingDataFlows[i]); + } + } + } + } + } + + return result; + } + + @Override + public boolean optimize(final BackendType backendType, final CompileUnit compileUnit, final ResolvedMethod method) { + + boolean changed = false; + + final Graph g = method.methodBody; + + // Variable and Constant propagation + final Stack workingQueue = new Stack<>(); + + // We search Copy operation to a variable. The Copy is followed by a single successor, and the target variable is only used + // by this successor. The variable can be replaced by the copy source if it is at the first place of the evaluation order + // of the successors incoming data flows. + g.nodes().stream().filter(t -> t.nodeType == NodeType.Copy).map(t -> (Copy) t).filter(t -> t.controlFlowsTo.size() == 1).forEach(workingQueue::push); + + // We perform a recursive search across the invocation graph + while (!workingQueue.isEmpty()) { + + final Copy workingItem = workingQueue.pop(); + + final Node source = workingItem.incomingDataFlows[0]; + + final Node[] outgoing = workingItem.outgoingDataFlows(); + if (outgoing.length == 1 && outgoing[0].nodeType == NodeType.Variable) { + final Variable variableToCheck = (Variable) outgoing[0]; + if (variableToCheck.incomingDataFlows.length == 1 && variableToCheck.outgoingDataFlows().length == 1) { + final ControlTokenConsumer successor = workingItem.controlFlowsTo.values().stream().findFirst().get(); + + final List evaluationOrder = evaluationOrderOf(successor); + + if (!evaluationOrder.isEmpty() && evaluationOrder.get(0) == variableToCheck) { + // We found a candidate + + g.remapDataFlow(variableToCheck, source); + + workingItem.deleteFromControlFlow(); + + g.deleteNode(variableToCheck); + + changed = true; + } + } + } + } + + return changed; + } + +} diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToUnusedPHI.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToUnusedPHI.java index 436ed28b74..18abb999c7 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToUnusedPHI.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/CopyToUnusedPHI.java @@ -1,3 +1,18 @@ +/* + * Copyright 2024 Mirko Sertic + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package de.mirkosertic.bytecoder.core.optimizer; import de.mirkosertic.bytecoder.core.backend.BackendType; diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java index 6507270b80..16f806741b 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java @@ -30,6 +30,7 @@ public enum Optimizations implements Optimizer { new PHIorVariableIsConstant(), new CopyToUnusedPHI(), new VariableIsVariable(), + new CopyToRedundantVariable(), new VirtualToDirectInvocation(), new DeleteRedundantClassInitializations() }), @@ -37,6 +38,7 @@ public enum Optimizations implements Optimizer { new PHIorVariableIsConstant(), new CopyToUnusedPHI(), new VariableIsVariable(), + new CopyToRedundantVariable(), new VirtualToDirectInvocation(), new DeleteRedundantClassInitializations() }), diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/PHIorVariableIsConstant.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/PHIorVariableIsConstant.java index a0eb2db810..63d8ce2d81 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/PHIorVariableIsConstant.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/PHIorVariableIsConstant.java @@ -56,7 +56,7 @@ public boolean optimize(final BackendType backendType, final CompileUnit compile final Node source = workingItem.incomingDataFlows[0]; // And only one outgoing dataflow // At this point we are sure it is a variable or phi - final Node target =g.outgoingDataFlowsFor(workingItem)[0]; + final Node target = g.outgoingDataFlowsFor(workingItem)[0]; g.remapDataFlow(target, source); diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md index 8da59a8aa9..25d9ef2174 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md @@ -34,3 +34,8 @@ JBox2D JS VarIsVar 3164444 bytes LUA Wasm VarIsVar 522726 bytes LUA JS VarIsVar 2376294 bytes + + JBox2D Wasm CopyToRedVar 517202 bytes + JBox2D JS CopyToRedVar 2576857 bytes + LUA Wasm CopyToRedVar 493149 bytes + LUA JS CopyToRedVar 2068370 bytes diff --git a/manual/static/docassets/ir_loopexample.svg b/manual/static/docassets/ir_loopexample.svg index 2947277c00..ea4ff2efce 100644 --- a/manual/static/docassets/ir_loopexample.svg +++ b/manual/static/docassets/ir_loopexample.svg @@ -1,403 +1,399 @@ - - - - - + debugoutput - + node_0 - -0 Region Start + +0 Region Start node_3 - -3 Copy + +3 Copy node_0->node_3 - - + + node_2 - -2 Variable : Lde/mirkosertic/bytecoder/IRExport; + +2 Variable : Lde/mirkosertic/bytecoder/IRExport; node_3->node_2 - - -arg 0 + + +arg 0 node_6 - -6 Copy + +6 Copy node_3->node_6 - - + + node_1 - -1 This : Lde/mirkosertic/bytecoder/IRExport; + +1 This : Lde/mirkosertic/bytecoder/IRExport; node_1->node_3 - - -arg 0 + + +arg 0 node_61 - -61 Copy + +61 Copy node_2->node_61 - - -arg 0 + + +arg 0 node_5 - -5 Variable : I + +5 Variable : I node_6->node_5 - - -arg 0 + + +arg 0 node_7 - -7 Region L1076607567 + +7 Region L572593338 node_6->node_7 - - + + node_4 - -4 MethodArgument : #0 + +4 MethodArgument : #0 node_4->node_6 - - -arg 0 + + +arg 0 node_10 - -10 Copy + +10 Copy node_5->node_10 - - -arg 0 + + +arg 0 node_62 - -62 Copy + +62 Copy node_5->node_62 - - -arg 0 + + +arg 0 node_8 - -8 LineNumberDebugInfo : line #27 + +8 LineNumberDebugInfo : line #27 node_7->node_8 - - + + node_8->node_10 - - + + node_9 - -9 Variable : I + +9 Variable : I node_10->node_9 - - -arg 0 + + +arg 0 node_12 - -12 Copy + +12 Copy node_10->node_12 - - + + node_9->node_12 - - -arg 0 + + +arg 0 node_11 - -11 Variable : I + +11 Variable : I node_12->node_11 - - -arg 0 + + +arg 0 node_13 - -13 Region L2036127838 + +13 Region L384294141 node_12->node_13 - - + + node_63 - -63 Copy + +63 Copy node_11->node_63 - - -arg 0 + + +arg 0 node_14 - -14 LineNumberDebugInfo : line #28 + +14 LineNumberDebugInfo : line #28 node_13->node_14 - - + + node_17 - -17 Copy + +17 Copy node_14->node_17 - - + + node_16 - -16 Variable : I + +16 Variable : I node_17->node_16 - - -arg 0 + + +arg 0 node_19 - -19 Copy + +19 Copy node_17->node_19 - - + + node_15 - -15 PrimitiveInt : 0 + +15 PrimitiveInt : 0 node_15->node_17 - - -arg 0 + + +arg 0 node_16->node_19 - - -arg 0 + + +arg 0 node_18 - -18 Variable : I + +18 Variable : I node_19->node_18 - - -arg 0 + + +arg 0 node_19->node_61 - - + + node_64 - -64 Copy + +64 Copy node_18->node_64 - - -arg 0 + + +arg 0 node_20 - -20 PHI : Lde/mirkosertic/bytecoder/IRExport; + +20 PHI : Lde/mirkosertic/bytecoder/IRExport; node_61->node_20 - - -arg 0 + + +arg 0 node_61->node_62 - - + + node_21 - -21 PHI : I + +21 PHI : I node_43 - -43 Copy + +43 Copy node_21->node_43 - - -arg 0 + + +arg 0 node_62->node_21 - - -arg 0 + + +arg 0 node_62->node_63 - - + + node_22 - -22 PHI : I + +22 PHI : I node_36 - -36 Copy + +36 Copy node_22->node_36 - - -arg 0 + + +arg 0 @@ -408,173 +404,173 @@ node_22->node_59 - + arg 0 node_63->node_22 - - -arg 0 + + +arg 0 node_63->node_64 - - + + node_65 - -65 Copy + +65 Copy node_65->node_22 - - -arg 1 + + +arg 1 node_24 - -24 Region L1509791656 + +24 Region L1024597427 node_65->node_24 - - + + node_23 - -23 PHI : I + +23 PHI : I node_27 - -27 Copy + +27 Copy node_23->node_27 - - -arg 0 + + +arg 0 node_38 - -38 Copy + +38 Copy node_23->node_38 - - -arg 0 + + +arg 0 node_52 - -52 Add + +52 Add node_23->node_52 - - -arg 0 + + +arg 0 node_53 - -53 Copy + +53 Copy node_53->node_23 - - -arg 0 + + +arg 0 node_54 - -54 Goto + +54 Goto node_53->node_54 - - + + node_64->node_23 - - -arg 1 + + +arg 1 node_64->node_24 - - + + node_25 - -25 FrameDebugInfo + +25 FrameDebugInfo node_24->node_25 - - + + node_25->node_27 - - + + node_26 - -26 Variable : I + +26 Variable : I node_27->node_26 - - -arg 0 + + +arg 0 node_30 - -30 Copy + +30 Copy node_27->node_30 - - + + @@ -585,99 +581,87 @@ node_26->node_32 - - -arg 0 + + +arg 0 node_29 - -29 Variable : I + +29 Variable : I node_30->node_29 - - -arg 0 + + +arg 0 node_31 - -31 If + +31 If node_30->node_31 - - + + node_28 - -28 PrimitiveInt : 100 + +28 PrimitiveInt : 100 node_28->node_30 - - -arg 0 + + +arg 0 node_29->node_32 - - -arg 1 + + +arg 1 - + -node_33 - -33 Region L944427387 +node_55 + +55 Region L1277009227 - + -node_31->node_33 - - -FALSE +node_31->node_55 + + +TRUE - + -node_55 - -55 Region L496729294 +node_33 + +33 Region L296347592 - + -node_31->node_55 - - -TRUE +node_31->node_33 + + +FALSE node_32->node_31 - - -arg 0 - - - -node_34 - -34 LineNumberDebugInfo : line #29 - - - -node_33->node_34 - - + + +arg 0 @@ -688,264 +672,276 @@ node_55->node_56 - - + + + + + +node_34 + +34 LineNumberDebugInfo : line #29 + + + +node_33->node_34 + + node_34->node_36 - - + + node_35 - -35 Variable : I + +35 Variable : I node_36->node_35 - - -arg 0 + + +arg 0 node_36->node_38 - - + + node_39 - -39 Add + +39 Add node_35->node_39 - - -arg 0 + + +arg 0 node_37 - -37 Variable : I + +37 Variable : I node_38->node_37 - - -arg 0 + + +arg 0 node_41 - -41 Copy + +41 Copy node_38->node_41 - - + + node_37->node_39 - - -arg 1 + + +arg 1 node_40 - -40 Variable : I + +40 Variable : I node_41->node_40 - - -arg 0 + + +arg 0 node_41->node_43 - - + + node_39->node_41 - - -arg 0 + + +arg 0 node_44 - -44 Add + +44 Add node_40->node_44 - - -arg 0 + + +arg 0 node_42 - -42 Variable : I + +42 Variable : I node_43->node_42 - - -arg 0 + + +arg 0 node_46 - -46 Copy + +46 Copy node_43->node_46 - - + + node_42->node_44 - - -arg 1 + + +arg 1 node_45 - -45 Variable : I + +45 Variable : I node_46->node_45 - - -arg 0 + + +arg 0 node_48 - -48 Copy + +48 Copy node_46->node_48 - - + + node_44->node_46 - - -arg 0 + + +arg 0 node_45->node_48 - - -arg 0 + + +arg 0 node_47 - -47 Variable : I + +47 Variable : I node_48->node_47 - - -arg 0 + + +arg 0 node_49 - -49 Region L1932831450 + +49 Region L315932542 node_48->node_49 - - + + node_47->node_65 - - -arg 0 + + +arg 0 node_50 - -50 LineNumberDebugInfo : line #28 + +50 LineNumberDebugInfo : line #28 node_49->node_50 - - + + node_50->node_53 - - + + node_51 - -51 PrimitiveInt : 1 + +51 PrimitiveInt : 1 node_51->node_52 - - -arg 1 + + +arg 1 node_52->node_53 - - -arg 0 + + +arg 0 node_54->node_65 - - + + diff --git a/manual/static/docassets/ir_loopexample_optimized.svg b/manual/static/docassets/ir_loopexample_optimized.svg index ad726570ac..9064eafdc0 100644 --- a/manual/static/docassets/ir_loopexample_optimized.svg +++ b/manual/static/docassets/ir_loopexample_optimized.svg @@ -1,841 +1,543 @@ - - - - - - + + debugoutput - + node_0 - -0 Region Start + +0 Region Start - + -node_3 - -3 Copy +node_2 + +2 Region L572593338 - + -node_0->node_3 - - +node_0->node_2 + + - + -node_2 - -2 Variable : Lde/mirkosertic/bytecoder/IRExport; +node_3 + +3 LineNumberDebugInfo : line #27 - + -node_3->node_2 - - -arg 0 - - - -node_6 - -6 Copy - - - -node_3->node_6 - - +node_2->node_3 + + node_1 - -1 This : Lde/mirkosertic/bytecoder/IRExport; + +1 MethodArgument : #0 - - -node_1->node_3 - - -arg 0 + + +node_34 + +34 Copy - - -node_51 - -51 Copy + + +node_1->node_34 + + +arg 0 + + + +node_21 + +21 Add + + + +node_1->node_21 + + +arg 1 + + + +node_4 + +4 Region L384294141 - - -node_2->node_51 - - -arg 0 + + +node_3->node_4 + + - + node_5 - -5 Variable : I + +5 LineNumberDebugInfo : line #28 + + + +node_4->node_5 + + - + -node_6->node_5 - - -arg 0 +node_5->node_34 + + - + node_7 - -7 Region L1076607567 + +7 PHI : I - - -node_6->node_7 - - + + +node_34->node_7 + + +arg 0 - - -node_4 - -4 MethodArgument : #0 + + +node_35 + +35 Copy - - -node_4->node_6 - - -arg 0 + + +node_34->node_35 + + - - -node_10 - -10 Copy + + +node_6 + +6 PrimitiveInt : 0 - - -node_5->node_10 - - -arg 0 + + +node_6->node_35 + + +arg 0 - - -node_52 - -52 Copy + + +node_17 + +17 Copy - - -node_5->node_52 - - -arg 0 + + +node_7->node_17 + + +arg 0 - - -node_8 - -8 LineNumberDebugInfo : line #27 + + +node_33 + +33 ReturnValue - - -node_7->node_8 - - + + +node_7->node_33 + + +arg 0 - - -node_8->node_10 - - + + +node_36 + +36 Copy + + + +node_36->node_7 + + +arg 1 - + node_9 - -9 Variable : I + +9 Region L1024597427 - - -node_10->node_9 - - -arg 0 - - - -node_11 - -11 Region L2036127838 + + +node_36->node_9 + + - - -node_10->node_11 - - + + +node_8 + +8 PHI : I - - -node_53 - -53 Copy + + +node_13 + +13 NumericalTest : GE - - -node_9->node_53 - - -arg 0 + + +node_8->node_13 + + +arg 0 - - -node_12 - -12 LineNumberDebugInfo : line #28 + + +node_19 + +19 Copy - - -node_11->node_12 - - + + +node_8->node_19 + + +arg 0 - - -node_12->node_51 - - + + +node_27 + +27 Add - - -node_14 - -14 PHI : Lde/mirkosertic/bytecoder/IRExport; + + +node_8->node_27 + + +arg 0 - - -node_51->node_14 - - -arg 0 + + +node_28 + +28 Copy - - -node_51->node_52 - - + + +node_28->node_8 + + +arg 0 - - -node_13 - -13 PrimitiveInt : 0 + + +node_29 + +29 Goto - - -node_54 - -54 Copy + + +node_28->node_29 + + - - -node_13->node_54 - - -arg 0 + + +node_35->node_8 + + +arg 1 - - -node_15 - -15 PHI : I + + +node_35->node_9 + + - - -node_35 - -35 Copy + + +node_10 + +10 FrameDebugInfo - - -node_15->node_35 - - -arg 0 + + +node_9->node_10 + + - - -node_52->node_15 - - -arg 0 + + +node_12 + +12 If - - -node_52->node_53 - - + + +node_10->node_12 + + - + -node_16 - -16 PHI : I +node_30 + +30 Region L1277009227 - - -node_28 - -28 Copy + + +node_12->node_30 + + +TRUE - - -node_16->node_28 - - -arg 0 - - - -node_49 - -49 Copy - - - -node_16->node_49 - - -arg 0 - - - -node_53->node_16 - - -arg 0 - - - -node_53->node_54 - - - - - -node_55 - -55 Copy + + +node_14 + +14 Region L296347592 - - -node_55->node_16 - - -arg 1 + + +node_12->node_14 + + +FALSE - - -node_18 - -18 Region L1509791656 + + +node_11 + +11 PrimitiveInt : 100 - - -node_55->node_18 - - + + +node_11->node_13 + + +arg 1 - - -node_17 - -17 PHI : I + + +node_13->node_12 + + +arg 0 - - -node_21 - -21 Copy + + +node_31 + +31 LineNumberDebugInfo : line #31 - - -node_17->node_21 - - -arg 0 + + +node_30->node_31 + + - - -node_30 - -30 Copy + + +node_15 + +15 LineNumberDebugInfo : line #29 - - -node_17->node_30 - - -arg 0 - - - -node_42 - -42 Add - - - -node_17->node_42 - - -arg 0 - - - -node_43 - -43 Copy + + +node_14->node_15 + + - - -node_43->node_17 - - -arg 0 - - - -node_44 - -44 Goto - - - -node_43->node_44 - - - - - -node_54->node_17 - - -arg 1 + + +node_15->node_17 + + - - -node_54->node_18 - - + + +node_16 + +16 Variable : I - - -node_19 - -19 FrameDebugInfo + + +node_17->node_16 + + +arg 0 - + -node_18->node_19 - - - - - -node_19->node_21 - - +node_17->node_19 + + - + node_20 - -20 Variable : I + +20 Add - - -node_21->node_20 - - -arg 0 + + +node_16->node_20 + + +arg 0 + + + +node_18 + +18 Variable : I + + + +node_19->node_18 + + +arg 0 - + node_23 - -23 If + +23 Copy - - -node_21->node_23 - - - - - -node_24 - -24 NumericalTest : GE + + +node_19->node_23 + + - - -node_20->node_24 - - -arg 0 + + +node_18->node_20 + + +arg 1 - - -node_25 - -25 Region L944427387 + + +node_22 + +22 Variable : I - - -node_23->node_25 - - -FALSE + + +node_23->node_22 + + +arg 0 - - -node_45 - -45 Region L496729294 + + +node_24 + +24 Region L315932542 - - -node_23->node_45 - - -TRUE + + +node_23->node_24 + + - - -node_22 - -22 PrimitiveInt : 100 + + +node_20->node_21 + + +arg 0 - + -node_22->node_24 - - -arg 1 +node_21->node_23 + + +arg 0 - - -node_24->node_23 - - -arg 0 + + +node_22->node_36 + + +arg 0 - - -node_26 - -26 LineNumberDebugInfo : line #29 + + +node_25 + +25 LineNumberDebugInfo : line #28 - - -node_25->node_26 - - - - - -node_46 - -46 LineNumberDebugInfo : line #31 - - - -node_45->node_46 - - - - + -node_26->node_28 - - +node_24->node_25 + + - - -node_27 - -27 Variable : I - - + -node_28->node_27 - - -arg 0 - - - -node_28->node_30 - - +node_25->node_28 + + - - -node_31 - -31 Add - - - -node_27->node_31 - - -arg 0 + + +node_26 + +26 PrimitiveInt : 1 - - -node_29 - -29 Variable : I + + +node_26->node_27 + + +arg 1 - + -node_30->node_29 - - -arg 0 +node_27->node_28 + + +arg 0 - - -node_33 - -33 Copy - - + -node_30->node_33 - - - - - -node_29->node_31 - - -arg 1 +node_29->node_36 + + - + node_32 - -32 Variable : I - - - -node_33->node_32 - - -arg 0 + +32 FrameDebugInfo - - -node_33->node_35 - - - - - -node_31->node_33 - - -arg 0 - - - -node_36 - -36 Add - - - -node_32->node_36 - - -arg 0 - - - -node_34 - -34 Variable : I - - - -node_35->node_34 - - -arg 0 - - - -node_38 - -38 Copy - - - -node_35->node_38 - - + + +node_31->node_32 + + - - -node_34->node_36 - - -arg 1 - - - -node_37 - -37 Variable : I - - - -node_38->node_37 - - -arg 0 - - - -node_39 - -39 Region L1932831450 - - - -node_38->node_39 - - - - - -node_36->node_38 - - -arg 0 - - - -node_37->node_55 - - -arg 0 - - - -node_40 - -40 LineNumberDebugInfo : line #28 - - - -node_39->node_40 - - - - - -node_40->node_43 - - - - - -node_41 - -41 PrimitiveInt : 1 - - - -node_41->node_42 - - -arg 1 - - - -node_42->node_43 - - -arg 0 - - - -node_44->node_55 - - - - - -node_47 - -47 FrameDebugInfo - - - -node_46->node_47 - - - - - -node_47->node_49 - - - - - -node_48 - -48 Variable : I - - - -node_49->node_48 - - -arg 0 - - - -node_50 - -50 ReturnValue - - - -node_49->node_50 - - - - - -node_48->node_50 - - -arg 0 + + +node_32->node_33 + + \ No newline at end of file