@@ -118,7 +118,8 @@ def compile
118
118
119
119
connect_local_graphs_control ( local_graphs )
120
120
connect_local_graphs_data ( local_graphs )
121
- cleanup
121
+ cleanup_phi_nodes
122
+ cleanup_insn_nodes
122
123
123
124
SeaOfNodes . new ( dfg , nodes , local_graphs ) . tap ( &:verify )
124
125
end
@@ -311,23 +312,13 @@ def connect_local_graphs_data(local_graphs)
311
312
# We don't always build things in an optimal way. Go back and fix up
312
313
# some mess we left. Ideally we wouldn't create these problems in the
313
314
# first place.
314
- def cleanup
315
+ def cleanup_phi_nodes
315
316
nodes . dup . each do |node | # dup because we're mutating
316
317
next unless node . is_a? ( PhiNode )
317
318
318
319
if node . inputs . size == 1
319
320
# Remove phi nodes with a single input.
320
- node . inputs . each do |producer_edge |
321
- node . outputs . each do |consumer_edge |
322
- connect (
323
- producer_edge . from ,
324
- consumer_edge . to ,
325
- producer_edge . type ,
326
- consumer_edge . label
327
- )
328
- end
329
- end
330
-
321
+ connect_over ( node )
331
322
remove ( node )
332
323
elsif node . inputs . map ( &:from ) . uniq . size == 1
333
324
# Remove phi nodes where all inputs are the same.
@@ -344,6 +335,66 @@ def cleanup
344
335
end
345
336
end
346
337
338
+ # Eliminate as many unnecessary nodes as we can.
339
+ def cleanup_insn_nodes
340
+ nodes . dup . each do |node |
341
+ next unless node . is_a? ( InsnNode )
342
+
343
+ case node . insn
344
+ when AdjustStack
345
+ # If there are any inputs to the adjust stack that are immediately
346
+ # discarded, we can remove them from the input list.
347
+ number = node . insn . number
348
+
349
+ node . inputs . dup . each do |input_edge |
350
+ next if input_edge . type != :data
351
+
352
+ from = input_edge . from
353
+ next unless from . is_a? ( InsnNode )
354
+
355
+ if from . inputs . empty? && from . outputs . size == 1
356
+ number -= 1
357
+ remove ( input_edge . from )
358
+ elsif from . insn . is_a? ( Dup )
359
+ number -= 1
360
+ connect_over ( from )
361
+ remove ( from )
362
+
363
+ new_edge = node . inputs . last
364
+ new_edge . from . outputs . delete ( new_edge )
365
+ node . inputs . delete ( new_edge )
366
+ end
367
+ end
368
+
369
+ if number == 0
370
+ connect_over ( node )
371
+ remove ( node )
372
+ else
373
+ next_node =
374
+ if number == 1
375
+ InsnNode . new ( Pop . new , node . offset )
376
+ else
377
+ InsnNode . new ( AdjustStack . new ( number ) , node . offset )
378
+ end
379
+
380
+ next_node . inputs . concat ( node . inputs )
381
+ next_node . outputs . concat ( node . outputs )
382
+
383
+ # Dynamically finding the index of the node in the nodes array
384
+ # because we're mutating the array as we go.
385
+ nodes [ nodes . index ( node ) ] = next_node
386
+ end
387
+ when Jump
388
+ # When you have a jump instruction that only has one input and one
389
+ # output, you can just connect over top of it and remove it.
390
+ if node . inputs . size == 1 && node . outputs . size == 1
391
+ connect_over ( node )
392
+ remove ( node )
393
+ end
394
+ end
395
+ end
396
+ end
397
+
347
398
# Connect one node to another.
348
399
def connect ( from , to , type , label = nil )
349
400
raise if from == to
@@ -354,6 +405,20 @@ def connect(from, to, type, label = nil)
354
405
to . inputs << edge
355
406
end
356
407
408
+ # Connect all of the inputs to all of the outputs of a node.
409
+ def connect_over ( node )
410
+ node . inputs . each do |producer_edge |
411
+ node . outputs . each do |consumer_edge |
412
+ connect (
413
+ producer_edge . from ,
414
+ consumer_edge . to ,
415
+ producer_edge . type ,
416
+ consumer_edge . label
417
+ )
418
+ end
419
+ end
420
+ end
421
+
357
422
# Remove a node from the graph.
358
423
def remove ( node )
359
424
node . inputs . each do |producer_edge |
0 commit comments