From 98ec4597d6bd615538326ce52c5bafcec7bf2d27 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 22 Sep 2023 10:21:26 +0200 Subject: [PATCH] Fix dominator tree algorithm --- .../teavm/common/DominatorTreeBuilder.java | 52 ++++-------- .../java/org/teavm/common/DomTreeTest.java | 84 +++++++++++++++++++ 2 files changed, 102 insertions(+), 34 deletions(-) create mode 100644 core/src/test/java/org/teavm/common/DomTreeTest.java diff --git a/core/src/main/java/org/teavm/common/DominatorTreeBuilder.java b/core/src/main/java/org/teavm/common/DominatorTreeBuilder.java index 63a60dba5..954fc21b7 100644 --- a/core/src/main/java/org/teavm/common/DominatorTreeBuilder.java +++ b/core/src/main/java/org/teavm/common/DominatorTreeBuilder.java @@ -30,7 +30,6 @@ class DominatorTreeBuilder { private int[] labels; int[] dominators; private IntegerArray[] bucket; - private int[] path; private int effectiveSize; private int start; @@ -44,7 +43,6 @@ class DominatorTreeBuilder { Arrays.fill(dominators, -1); ancestors = new int[graph.size()]; labels = new int[graph.size()]; - path = new int[graph.size()]; bucket = new IntegerArray[graph.size()]; } @@ -54,32 +52,22 @@ class DominatorTreeBuilder { } Arrays.fill(ancestors, -1); dfs(); - for (int i = effectiveSize - 1; i >= 0; --i) { + for (int i = effectiveSize - 1; i > 0; --i) { int w = vertices[i]; - if (parents[w] < 0) { - continue; - } - if (w != start) { - for (int v : graph.incomingEdges(w)) { - int u = eval(v); - if (semidominators[u] >= 0) { - semidominators[w] = Math.min(semidominators[w], semidominators[u]); - } - } + for (int v : graph.incomingEdges(w)) { + int u = eval(v); + semidominators[w] = Math.min(semidominators[w], semidominators[u]); } addToBucket(vertices[semidominators[w]], w); link(parents[w], w); - for (int v : getBucket(w)) { + for (int v : getBucket(parents[w])) { int u = eval(v); dominators[v] = semidominators[u] < semidominators[v] ? u : parents[w]; } bucket[w] = null; } - for (int i = 0; i < effectiveSize; ++i) { + for (int i = 1; i < effectiveSize; ++i) { int w = vertices[i]; - if (w < 0 || parents[w] < 0) { - continue; - } if (dominators[w] != vertices[semidominators[w]]) { dominators[w] = dominators[dominators[w]]; } @@ -107,27 +95,23 @@ class DominatorTreeBuilder { private int eval(int v) { int ancestor = ancestors[v]; - if (ancestor == -1) { + if (ancestor < 0) { return v; } - int i = 0; - while (ancestor >= 0) { - path[i++] = v; - v = ancestor; - ancestor = ancestors[v]; - } - ancestor = v; - while (--i >= 0) { - v = path[i]; - if (semidominators[labels[v]] > semidominators[labels[ancestor]]) { - labels[v] = labels[ancestor]; - } - ancestors[v] = ancestor; - ancestor = v; - } + compress(v); return labels[v]; } + private void compress(int v) { + if (ancestors[ancestors[v]] >= 0) { + compress(ancestors[v]); + if (semidominators[labels[ancestors[v]]] < semidominators[labels[v]]) { + labels[v] = labels[ancestors[v]]; + } + ancestors[v] = ancestors[ancestors[v]]; + } + } + private void dfs() { Arrays.fill(semidominators, -1); Arrays.fill(vertices, -1); diff --git a/core/src/test/java/org/teavm/common/DomTreeTest.java b/core/src/test/java/org/teavm/common/DomTreeTest.java new file mode 100644 index 000000000..39cb38ad7 --- /dev/null +++ b/core/src/test/java/org/teavm/common/DomTreeTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2023 Alexey Andreev. + * + * 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 org.teavm.common; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class DomTreeTest { + @Test + public void domTree1() { + var builder = new GraphBuilder(); + addEdges(builder, 0, 16, 17); + addEdges(builder, 1, 14); + addEdges(builder, 2, 18); + addEdges(builder, 3, 6, 7, 15); + addEdges(builder, 4, 11, 15, 26); + addEdges(builder, 5, 11, 15, 30); + addEdges(builder, 6); + addEdges(builder, 7, 15, 34); + addEdges(builder, 8, 15); + addEdges(builder, 9, 13, 15, 38); + addEdges(builder, 10, 11, 15, 42); + addEdges(builder, 11, 8, 9, 15); + addEdges(builder, 12, 8, 15); + addEdges(builder, 13, 8, 15); + addEdges(builder, 14, 10, 15); + addEdges(builder, 15); + addEdges(builder, 16, 1, 2); + addEdges(builder, 17, 16, 20, 24, 28, 32, 36, 40, 44); + addEdges(builder, 18, 19, 21); + addEdges(builder, 19, 22); + addEdges(builder, 20, 18); + addEdges(builder, 21); + addEdges(builder, 22, 23, 25); + addEdges(builder, 23); + addEdges(builder, 24, 22); + addEdges(builder, 25); + addEdges(builder, 26, 11, 15, 27, 29); + addEdges(builder, 27, 5, 11, 15); + addEdges(builder, 28, 26); + addEdges(builder, 29); + addEdges(builder, 30, 11, 15, 31, 33); + addEdges(builder, 31, 3, 4, 11, 15); + addEdges(builder, 32, 30); + addEdges(builder, 33); + addEdges(builder, 34, 15, 35, 37); + addEdges(builder, 35, 6, 15); + addEdges(builder, 36, 34); + addEdges(builder, 37); + addEdges(builder, 38, 13, 15, 39, 41); + addEdges(builder, 39, 12, 13, 15); + addEdges(builder, 40, 38); + addEdges(builder, 41); + addEdges(builder, 42, 11, 15, 43, 45); + addEdges(builder, 43, 5, 11, 15); + addEdges(builder, 44, 42); + addEdges(builder, 45); + + var graph = builder.build(); + var dom = GraphUtils.buildDominatorTree(graph); + assertEquals(0, dom.immediateDominatorOf(8)); + assertEquals(17, dom.immediateDominatorOf(44)); + assertEquals(11, dom.immediateDominatorOf(9)); + } + + private static void addEdges(GraphBuilder builder, int from, int... to) { + for (int target : to) { + builder.addEdge(from, target); + } + } +}