85 lines
2.2 KiB
Smalltalk
85 lines
2.2 KiB
Smalltalk
|
"
|
||
|
As I traverste the graph, I find equivalent nodes and I merge the equivalent nodes under the single one.
|
||
|
|
||
|
This saves compiler time, number of instance variables needed and makes compiled class more compact.
|
||
|
|
||
|
I am using `node:equals:` because of performance (I do cache allNodes) which took too much time to constantly compute...
|
||
|
"
|
||
|
Class {
|
||
|
#name : 'PPCMergingVisitor',
|
||
|
#superclass : 'PPCRewritingVisitor',
|
||
|
#instVars : [
|
||
|
'nodeSet',
|
||
|
'childrenCache'
|
||
|
],
|
||
|
#category : 'PetitCompiler-Visitors'
|
||
|
}
|
||
|
|
||
|
{ #category : 'children cache' }
|
||
|
PPCMergingVisitor >> cachedChildren: node [
|
||
|
^ childrenCache at: node ifAbsentPut: [
|
||
|
node dfsOrder
|
||
|
]
|
||
|
]
|
||
|
|
||
|
{ #category : 'node comparison' }
|
||
|
PPCMergingVisitor >> equivalentNode: node [
|
||
|
self halt: 'not used?'.
|
||
|
^ nodeSet detect: [ :e | self node: e equals: node ]
|
||
|
]
|
||
|
|
||
|
{ #category : 'node comparison' }
|
||
|
PPCMergingVisitor >> equivalentNode: node ifNone: block [
|
||
|
^ nodeSet detect: [ :e | self node: e equals: node ] ifNone: block
|
||
|
]
|
||
|
|
||
|
{ #category : 'node comparison' }
|
||
|
PPCMergingVisitor >> hasEquivalentNode: node [
|
||
|
^ nodeSet contains: [ :e | self node: e equals: node ]
|
||
|
]
|
||
|
|
||
|
{ #category : 'initialization' }
|
||
|
PPCMergingVisitor >> initialize [
|
||
|
super initialize.
|
||
|
|
||
|
"Though this is IdentitySet, I do assert node:equals: befoere inserting node into the set"
|
||
|
nodeSet := IdentitySet new.
|
||
|
childrenCache := IdentityDictionary new.
|
||
|
]
|
||
|
|
||
|
{ #category : 'node comparison' }
|
||
|
PPCMergingVisitor >> node: node equals: anotherNode [
|
||
|
| children anotherChildren |
|
||
|
(node equals: anotherNode) ifFalse: [ ^ false ].
|
||
|
|
||
|
children := self cachedChildren: node.
|
||
|
anotherChildren := self cachedChildren: anotherNode.
|
||
|
|
||
|
(children size = anotherChildren size) ifFalse: [ ^ false ].
|
||
|
|
||
|
children with: anotherChildren do: [ :n1 :n2 |
|
||
|
(n1 equals: n2) ifFalse: [ ^ false ]
|
||
|
].
|
||
|
^ true
|
||
|
]
|
||
|
|
||
|
{ #category : 'node comparison' }
|
||
|
PPCMergingVisitor >> store: node [
|
||
|
self assert: (self hasEquivalentNode: node) not.
|
||
|
nodeSet add: node
|
||
|
]
|
||
|
|
||
|
{ #category : 'traversing' }
|
||
|
PPCMergingVisitor >> visitNode: node [
|
||
|
| equivalent |
|
||
|
"merge the conntent of the node"
|
||
|
super visitNode: node.
|
||
|
|
||
|
(equivalent := self equivalentNode: node ifNone: nil ) isNil ifFalse: [
|
||
|
self cache: node value: equivalent.
|
||
|
^ equivalent
|
||
|
].
|
||
|
self store: node.
|
||
|
^ node
|
||
|
]
|