Skip to content

Commit

Permalink
Expanding AliasAnalysisTest with if/then section
Browse files Browse the repository at this point in the history
  • Loading branch information
JaroslavTulach committed Nov 7, 2024
1 parent bfc4969 commit aa93b06
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,18 @@ protected IgnoredBindings.State readObject(Input in)
@org.openide.util.lookup.ServiceProvider(service = Persistance.class)
public static final class PersistAliasAnalysisGraphScope extends Persistance<Graph.Scope> {
public PersistAliasAnalysisGraphScope() {
super(Graph.Scope.class, false, 1269);
super(Graph.Scope.class, false, 1270);
}

@Override
@SuppressWarnings("unchecked")
protected Graph.Scope readObject(Input in) throws IOException {
var flatten = in.readBoolean();
var childScopes = in.readInline(scala.collection.immutable.List.class);
var occurrencesValues = (scala.collection.immutable.Set<GraphOccurrence>) in.readObject();
var occurrences = occurrencesValues.map(v -> Tuple2$.MODULE$.apply(v.id(), v)).toMap(null);
var allDefinitions = in.readInline(scala.collection.immutable.List.class);
var parent = new Graph.Scope(childScopes, occurrences, allDefinitions);
var parent = new Graph.Scope(flatten, childScopes, occurrences, allDefinitions);
childScopes.forall(
(object) -> {
var ch = (Graph.Scope) object;
Expand All @@ -116,6 +117,7 @@ protected Graph.Scope readObject(Input in) throws IOException {
@Override
@SuppressWarnings("unchecked")
protected void writeObject(Graph.Scope obj, Output out) throws IOException {
out.writeBoolean(obj.flattenToParent());
out.writeInline(scala.collection.immutable.List.class, obj.childScopes());
out.writeObject(obj.occurrences().values().toSet());
out.writeInline(scala.collection.immutable.List.class, obj.allDefinitions());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
public final class GraphBuilder {
private final Graph graph;
private final Graph.Scope scope;
private final boolean flattenToParent;

private GraphBuilder(Graph graph, Graph.Scope scope) {
private GraphBuilder(Graph graph, Graph.Scope scope, boolean flattenToParent) {
this.graph = graph;
this.scope = scope;
this.flattenToParent = flattenToParent;
}

/**
Expand All @@ -31,16 +33,27 @@ public static GraphBuilder create() {
* @return builder operating on the graph {@code g} starting at scope {@code s}
*/
public static GraphBuilder create(Graph g, Graph.Scope s) {
return new GraphBuilder(g, s);
return new GraphBuilder(g, s, false);
}

/**
* Creates a child scope and returns a builder for it.
* Creates a child scope and returns a builder for it. Same as calling {@link #addChild(boolean)}
* with {@code false} argument.
*
* @return new builder for newly created scope, but the same graph
*/
public GraphBuilder addChild() {
return new GraphBuilder(graph, scope.addChild());
return addChild(false);
}

/**
* Creates a child scope and returns a builder for it.
*
* @param flattenToParent flatten definitions into parent
* @return new builder for newly created scope, but the same graph
*/
public GraphBuilder addChild(boolean flattenToParent) {
return new GraphBuilder(graph, scope.addChild(flattenToParent), flattenToParent);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class LocalScope(
log: BiFunction[String, Array[Object], Void]
): java.util.List[String] = {
def symbols(): java.util.List[String] = {
val r = scope.allDefinitions.map(_.symbol)
val r = scope.allDefinitionsWithFlattened.map(_.symbol)
r.asJava
}
val meta = if (symbolsProvider == null) null else symbolsProvider()
Expand Down Expand Up @@ -141,7 +141,7 @@ class LocalScope(
* internal slots, that are prepended to every frame.
*/
private def gatherLocalFrameSlotIdxs(): Map[AliasGraph.Id, Int] = {
scope.allDefinitions.zipWithIndex.map { case (definition, i) =>
scope.allDefinitionsWithFlattened.zipWithIndex.map { case (definition, i) =>
definition.id -> (i + LocalScope.internalSlotsSize)
}.toMap
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package alias.graph

import org.enso.compiler.core.CompilerError
import org.enso.compiler.debug.Debug
import org.enso.compiler.pass.analyse.FramePointer
import org.enso.compiler.pass.analyse.alias.graph.Graph.Scope

import scala.collection.immutable.HashMap
Expand All @@ -13,7 +14,7 @@ import scala.annotation.unused

/** A graph containing aliasing information for a given root scope in Enso. */
sealed class Graph(
val rootScope: Graph.Scope = new Graph.Scope(),
val rootScope: Graph.Scope = new Graph.Scope(false),
private var _nextIdCounter: Int = 0,
private var links: Set[Graph.Link] = Set()
) {
Expand Down Expand Up @@ -104,6 +105,48 @@ sealed class Graph(
link
})
}
final def resolveFramePointer(
occurrence: GraphOccurrence.Def
): Option[FramePointer] = {
var useScope = scopeFor(occurrence.id)
while (useScope.nonEmpty) {
if (!useScope.get.flattenToParent) {
return useScope
.map(_.allDefinitionsWithFlattened.indexOf(occurrence))
.filter(_ >= 0)
.map(new FramePointer(0, _))
}
useScope = useScope.get.parent
}
None
}

final def resolveFramePointer(
occurrence: GraphOccurrence.Use
): Option[FramePointer] = {
val link = resolveLocalUsage(occurrence)
if (link.isEmpty) {
return None
}
var parentsUp = 0
val useScope = scopeFor(occurrence.id)
if (useScope.nonEmpty) {
var currentScope = useScope.get
while (currentScope != null) {
if (!currentScope.flattenToParent) {
val at = currentScope.allDefinitionsWithFlattened.indexWhere(
_.id == link.get.target
)
if (at >= 0) {
return Some(new FramePointer(parentsUp, at))
}
parentsUp += 1
}
currentScope = currentScope.parent.orNull
}
}
None
}

private def addSourceTargetLink(link: Graph.Link): Unit = {
// commented out: used from DebugEvalNode
Expand Down Expand Up @@ -320,18 +363,24 @@ object Graph {
* @param allDefinitions all definitions in this scope, including synthetic ones.
* Note that there may not be a link for all these definitions.
*/
sealed class Scope(
sealed class Scope private[Graph] (
private[analyse] val flattenToParent: Boolean,
private[Graph] var _childScopes: List[Scope] = List(),
private[Graph] var _occurrences: Map[Id, GraphOccurrence] = HashMap(),
private[Graph] var _allDefinitions: List[GraphOccurrence.Def] = List()
) {

private[Graph] var _parent: Scope = null

def childScopes = _childScopes
def occurrences = _occurrences
def childScopes = _childScopes
def occurrences = _occurrences
def allDefinitions = _allDefinitions
def parent = if (this._parent eq null) None else Some(_parent)
def allDefinitionsWithFlattened: List[GraphOccurrence.Def] = {
_allDefinitions ++ _childScopes
.filter(_.flattenToParent)
.flatMap(_.allDefinitionsWithFlattened)
}
def parent = if (this._parent eq null) None else Some(_parent)

/** Counts the number of scopes from this scope to the root.
*
Expand All @@ -340,7 +389,8 @@ object Graph {
* @return the number of scopes from this scope to the root
*/
private[analyse] def scopesToRoot: Int = {
parent.flatMap(scope => Some(scope.scopesToRoot + 1)).getOrElse(0)
val plusMine = if (flattenToParent) 0 else 1
parent.flatMap(scope => Some(scope.scopesToRoot + plusMine)).getOrElse(0)
}

/** Sets the parent of the scope.
Expand Down Expand Up @@ -375,9 +425,10 @@ object Graph {
)
val newScope =
new Scope(
flattenToParent,
childScopeCopies.toList,
occurrences,
allDefinitions
_occurrences,
_allDefinitions
)
mapping.put(this, newScope)
newScope
Expand Down Expand Up @@ -406,14 +457,13 @@ object Graph {

/** Creates and returns a scope that is a child of this one.
*
* @param is this scope "just virtual" and will be flatten to parent at the end?
* @param flattenToParent is this scope "just virtual" and will be flatten to parent at the end?
* @return a scope that is a child of `this`
*/
private[graph] def addChild(): Scope = {
val scope = new Scope()
private[graph] def addChild(flattenToParent: Boolean): Scope = {
val scope = new Scope(flattenToParent)
scope._parent = this
_childScopes ::= scope

_childScopes = _childScopes.appended(scope)
scope
}

Expand Down Expand Up @@ -656,7 +706,7 @@ object Graph {
}

private def removeScopeFromParent(scope: Scope): Unit = {
_childScopes = childScopes.filter(_ != scope)
_childScopes = _childScopes.filter(_ != scope)
}

/** Disassociates this Scope from its parent.
Expand All @@ -676,7 +726,7 @@ object Graph {
* @param scopeCount the number of scopes that the link traverses
* @param target the target ID of the link in the graph
*/
sealed private[analyse] case class Link(
sealed private[analyse] case class Link private[Graph] (
source: Id,
scopeCount: Int,
target: Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ class AliasAnalysisTest extends CompilerTest {
"The analysis scope" should {
val builder = GraphBuilder.create()

val flatScope = GraphBuilder.create().toScope();
val flatScope = GraphBuilder.create().toScope()

val complexScope = GraphBuilder.create().toScope();
val complexScope = GraphBuilder.create().toScope()
val complexBuilder = GraphBuilder.create(null, complexScope)
val child1 = complexBuilder.addChild()
val child2 = complexBuilder.addChild()
Expand Down Expand Up @@ -232,6 +232,76 @@ class AliasAnalysisTest extends CompilerTest {
complexScope.scopesToRoot shouldEqual 0
}
}
"if_then_doubled example" should {
val root = GraphBuilder.create()

val ifCond1 = root.addChild()
val ifTrue1 = root.addChild(true)

val ifCond2 = root.addChild()
val ifTrue2 = root.addChild(true)

val aDef = root.newDef("a", genId, None)
root.add(aDef)
root.addDefinition(aDef)

val aUse1 = ifCond1.newUse("a", genId, None)
ifCond1.add(aUse1)
val aUse2 = ifCond2.newUse("a", genId, None)
ifCond2.add(aUse2)

val xDef1 = ifTrue1.newDef("x", genId, None)
ifTrue1.add(xDef1)
ifTrue1.addDefinition(xDef1)
val xUse1 = ifTrue1.newUse("x", genId, None)
ifTrue1.add(xUse1)

val xDef2 = ifTrue1.newDef("x", genId, None)
ifTrue2.add(xDef2)
ifTrue2.addDefinition(xDef2)
val xUse2 = ifTrue2.newUse("x", genId, None)
ifTrue2.add(xUse2)

val rootScope = root.toScope()
val rootGraph = root.toGraph()

"have four subscopes" in {
rootScope.scopeCount shouldEqual 5
}

"frame needs two slots for x" in {
val all = rootScope.allDefinitionsWithFlattened
all shouldEqual List(aDef, xDef1, xDef2)
}

"are uses different" in {
xUse1.id should not equal xUse2.id
}

"frame pointer for definition of a" in {
val fp = rootGraph.resolveFramePointer(aDef)
fp.get.parentLevel shouldEqual 0
fp.get.frameSlotIdx shouldEqual 0
}

"xUse1 uses xDef1" in {
val link = rootGraph.resolveLocalUsage(xUse1)
link.get.target shouldEqual xDef1.id

val fp = rootGraph.resolveFramePointer(xUse1)
fp.get.parentLevel.shouldEqual(0)
fp.get.frameSlotIdx.shouldEqual(1)
}

"xUse2 uses xDef2" in {
val link = rootGraph.resolveLocalUsage(xUse2)
link.get.target shouldEqual xDef2.id

val fp = rootGraph.resolveFramePointer(xUse2)
fp.get.parentLevel.shouldEqual(0)
fp.get.frameSlotIdx.shouldEqual(2)
}
}

"The Aliasing graph" should {
val builder = GraphBuilder.create()
Expand Down

0 comments on commit aa93b06

Please sign in to comment.