# widen.tcl --
#
#	Transformation that inserts type-widening operations into
#	quadcode sequences
#
# Copyright (c) 2015 by Kevin B. Kenny
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
#------------------------------------------------------------------------------

# widen --
#
#	Inserts type widening operations where necessary.
#
# Results:
#	None.
#
# Side effects:
#	'widen' operations are inserted in the quadcode.
#
# The only place where widening is necessary is where values of
# different types meet at a phi operation. When that happens, the
# result type of the phi has been determined (before this procedure
# executes) to be the union of the argument types. This method
# simply drops in 'widen' operations to flag to the code issuer that
# the internal representation of the values may need to change.

oo::define quadcode::transformer method widen {} {
    my debug-widen {
	puts "widen:"
	my dump-bb
    }

    # Find and widen the inputs of all the phi operations in the program
    set b -1
    foreach content $bbcontent {
	incr b

	set pc -1
	foreach q $content {
	    incr pc
	    if {[lindex $q 0] ne "phi"} continue

	    set destvar [lindex $q 1]
	    set desttype [dict get $types $destvar]
	    
	    # Examine each input to a phi
	    set i 2
	    foreach {from source} [lrange $q 2 end] {
		if {[typeOfOperand $types $source] != $desttype} {

		    # $source needs to be widened. Make a new temporary
		    # to hold the widened value, and insert a 'widen'
		    # operation in the basic block that got here.
		    set frombb [lindex $from 1]
		    set fromcontent [lindex $bbcontent $frombb]
		    lset bbcontent $frombb {}
		    set lastjump [lindex $fromcontent end]
		    set fromcontent \
			[lreplace $fromcontent[set fromcontent {}] end end]
		    set newvar [my newVarInstance $destvar]
		    lappend fromcontent \
			[list [list widenTo $desttype [nameOfType $desttype]] \
			     $newvar $source] \
			$lastjump
		    lset bbcontent $frombb $fromcontent
		    lset bbcontent $b $pc [expr {$i+1}] $newvar
		    dict set udchain $newvar $frombb
		    my addUse $newvar $b
		    my removeUse $source $b
		    my addUse $source $frombb
		    dict set types $newvar $desttype
		}
		incr i 2
	    }
	}

	# Also widen the operand of any 'return' instruction

	# Make sure we have the current content of the basic block
	set content [lindex $bbcontent $b]
	set q [lindex $content end]
	if {[lindex $q 0] eq "return"} {

	    set source [lindex $q 3]
	    set desttype [dict get $types "return"]
	    if {[typeOfOperand $types $source] != $desttype} {

		# The return value needs to be widened
		set newvar [my newVarInstance {temp 0}]
		lset bbcontent $b {}
		set content \
		    [lreplace $content[set content {}] end end \
			 [list [list widenTo $desttype [nameOfType $desttype]] \
			      $newvar $source] \
			 [list return {} [lindex $q 2] $newvar]]
		lset bbcontent $b $content
		dict set udchain $newvar $b
		my addUse $newvar $b
		my removeUse $source $b
		dict set types $newvar $desttype
	    }
	}
    }


    my debug-widen {
	puts "after widen:"
	my dump-bb
    }
}
