# build.tcl --
#
#	Implementations of the quadcodes in LLVM IR, and wrapper round the
#	builder objects in llvmtcl. Many of the implementations are issued as
#	calls to mandatory-inline functions, so that they can inject extra
#	basic blocks without disturbing the analysis from the reasoning
#	engine.
#
#	Also includes code to automatically widen operation types and make the
#	code for issuing instructions simpler.
#
# Copyright (c) 2014-2015 by Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
#------------------------------------------------------------------------------

# Class Builder --
#
#	This class handles actual LLVM instruction issuing. Its members can be
#	categorized into simple instruction issuers that are just wrappers
#	around the relevant LLVM IR instruction (e.g., 'add'), simple
#	instruction issuers that are just wrappers around an (inline-able)
#	call to the relevant library function (e.g., 'addReference'), typed
#	instruction issuers that are called from the compilation engine (e.g.,
#	'add(INT,INT)'; note that many but not all of these are defined by
#	calling library functions), support methods defined in stdlib.tcl that
#	are responsbile for creating the library functions (e.g.,
#	'@supportFunctions', '@apiFunctions'), and support methods responsible
#	for doing type widening (i.e., 'unknown', 'MakeTypecastWrapper').
#
# Construction Parameters:
#	builder (optional) -
#		The llvmtcl builder handle; if omitted, one will be created
#		(and automatically deleted when this wrapping object is
#		deleted).
#
# Public properties:
#	ref -	The llvmtcl builder handle.
#	@cur -	The current basic block handle, or empty string if this
#		builder has never been assigned to a basic block.

oo::class create Builder {
    superclass llvmEntity
    variable b module dispose currentblock

    constructor {{builder ""}} {
	next
	set dispose [expr {$builder eq ""}]
	if {$dispose} {
	    set b [CreateBuilder]
	} else {
	    set b $builder
	}

	# --------------------------------------------------------------------
	# THE FOLLOWING FUNCTIONS CAN ONLY BE USED FROM INSIDE METHODS OF THIS
	# CLASS OR ITS SUBCLASSES. They make gross assumptions about how they
	# are used; violating them will cause errors and may trigger LLVM to
	# panic. They are designed to make stdlib.tcl more comprehensible and
	# less error-prone to write.
	# --------------------------------------------------------------------

	# label --
	#
	#	Mark the start of a block, assigning the block to a variable.
	#	Note that the block is actually created by [build]; [label]
	#	should only be used inside a [build] script.
	#
	# Parameters:
	#	name -	The name of the variable that will hold this label. It
	#		will have any trailing colon (which should only be
	#		present when no labelName is given) removed.
	#	labelName (optional) -
	#		The name of the label in the LLVM IR. If omitted, the
	#		variable name will be used instead. WARNING! The label
	#		name MUST be enclosed in double quotes for the parser
	#		in [build] to pick it up!
	#
	# Results:
	#	None.
	#
	# Side effects:
	#	Sets the current build point to the block with the label in
	#	the variable whose name is passed in.

	proc label {name {labelName ""}} {
	    upvar 1 [string trimright $name ":"] block
	    my @end $block
	    return
	}

	# params --
	#
	#	Get the parameters from a function declaration (the handle to
	#	which MUST be in the 'f' variable) and give them names and
	#	assign them to variables.
	#
	# Parameters:
	#	args -	The variable descriptors. Each variable descriptor
	#		must be either in the form 'abc' or 'abc:def'; the
	#		first form is a special case shorthand for 'abc:abc').
	#		The 'abc' part gives the name of the variable to
	#		assign the value reference to, and the 'def' part
	#		gives the name to give the parameter in the LLVM IR.
	#
	# Results:
	#	The list of parameter values, as LLVM IR value references.
	#
	# Side effects:
	#	Assigns to each of the named variables. These SHOULD be local
	#	variables; the values assigned to them are local to the
	#	context function.

	proc params {args} {
	    upvar 1 f func
	    set idx 0
	    set result {}
	    foreach param $args {
		if {[regexp {^([^:]+):(.*)$} $param -> name label]} {
		    upvar $name p
		    set p [$func param $idx $label]
		} else {
		    upvar $param p
		    set p [$func param $idx $param]
		}
		lappend result $p
		incr idx
	    }
	    return $result
	}

	# build --
	#
	#	Create a context in which the code for the current function
	#	(WARNING: in the 'f' variable) is issued. This context serves
	#	two purposes:
	# 
	#	1. Managing the collection of basic blocks so that they are
	#	   declared at the start (by pre-parsing for the embedded
	#	   [label] command). Note that the initial basic block is
	#	   stored in the variable 'entry'.
	#
	#	2. Limiting the scope of variables created within the function
	#	   for the holding of intermediate values so that intermediate
	#	   values in one function are not inadvertently used in
	#	   another (which causes a tricky-to-debug failure to
	#	   validate).
	#
	#	It also applies function-level validation to the resulting
	#	function, so that any problems at least generate a warning
	#	early. (Validation failures at that point cannot discover what
	#	the reason for failure is, so warnings are all that can be
	#	issued. The full module validation later will provide further
	#	information.)
	#
	#	WARNING: THIS CODE IS COMPLICATED AND A BIT FRAGILE!
	#
	# Parameters:
	#	script -
	#		The Tcl script that defines the function. NOTE: Tcl
	#		variables created in this script will not persist past
	#		the end of the script. This script will be run with
	#		the current namespace being the same as the builder
	#		object.
	#
	# Results:
	#	The list of parameter values, as LLVM IR value references.
	#
	# Side effects:
	#	Defines the function. DOES NOT (permanently) CHANGE THE
	#	BUILDER'S CONTEXT BLOCK.

	proc build {script} {
	    upvar 1 f func entry entry

	    # Parse the script and create the basic blocks
	    set entry [$func block]
	    set RE {(?xn)			# Extended + line mode
		^ \s*
		label				# The [label] command ...
		\s+
		([\w(.)]+)			# The name parameter
		(?: \s+ " ([^""]*) " )?		# The ?labelName? parameter
		:?				# Optional colon
		\s* $
	    }
	    set blocks [set blockNames {}]
	    foreach {- name desc} [regexp -all -inline $RE $script] {
		lappend blockNames $name
		if {$desc eq ""} {
		    lappend blocks [$func block $name]
		} else {
		    lappend blocks [$func block $desc]
		}
		# Sanity check
		if {[incr names($name)] > 1} {
		    puts "WARNING: label \"$name\" occurs twice in [$f name]"
		}
	    }

	    # Save the builder context block and point it to the function's
	    # entry point.
	    set cur [my @cur]
	    my @end $entry

	    # Construct the wrapping lambda term.
	    set initvars {upvar 1}
	    foreach v [uplevel 1 {info vars}] {
		lappend initvars $v $v
	    }
	    append initvars ";"
	    foreach name $blockNames block $blocks {
		append initvars [list set $name $block] ";"
	    }
	    set lambda [list {} $initvars$script [uplevel 1 namespace current]]

	    # Run the script. This will pick up the caller's current variables
	    # yet limit the variables inside the script to just the script.
	    try {
		uplevel 1 [list apply $lambda]
	    } on error {a b} {
		# Strip the parts of the stack trace that are confusing bits
		# and pieces of the machinery of the [build] procedure.
		set info [lrange [split [dict get $b -errorinfo] \n] 0 end-5]
		lset info end \
		    [regsub {lambda term ".*" line (\d+)} \
			 [lindex $info end] \
			 "function \"[$func name]\" body script line \\1"]
		dict set b -errorinfo [join $info \n]
		dict incr b -level
		return -options $b $a
	    }

	    # Verify the function and reset the builder context.
	    $func verify
	    my @end $cur
	    return
	}
    }

    destructor {
	if {$dispose} {
	    DisposeBuilder $b
	}
    }

    # Builder:ref (property) --
    #
    #	Get the llvmtcl builder reference, necessary if you are calling the
    #	llvmtcl API directly.

    method ref {} {
	return $b
    }

    # Builder:@end --
    #
    #	Set the current builder context to the end of the given basic block.
    #
    # Parameters:
    #	block -	The handle of the basic block object (an instance of the
    #		Block class). If this is the empty string, no action is taken
    #		(so that resetting to a value return by the '@cur' method can
    #		be done blindly).
    #	body (optional) -
    #		A script to run after setting the basic block.
    #
    # Results:
    #	The basic block object.

    method @end {block {body ""}} {
	if {$block ne ""} {
	    set currentblock $block
	    PositionBuilderAtEnd $b [$block ref]
	}
	uplevel 1 $body
	return $block
    }

    # Builder:@cur (property) --
    #
    #	Get the current basic block, or the empty string if there is no
    #	current basic block (an initial state only).

    method @cur {} {
	if {![info exist currentblock]} {
	    return ""
	}
	return $currentblock
    }
    export @end @cur

    # Builder:unknown --
    #
    #	Interceptor for method calls that are not already present. Delegates
    #	the test for whether we want to take action on this to the
    #	'MakeTypecastWrapper' method; if that returns true, we *replace* this
    #	unknown method call with a call to the (newly created) method.
    #
    # Parameters:
    #	FOLLOWS STANDARD TclOO PROTOCOL
    #
    # Results:
    #	FOLLOWS STANDARD TclOO PROTOCOL
    #
    # Side effects:
    # 	May create a method. May perform a tailcall (beware if attempting to
    # 	wrap with a filter!)

    method unknown {methodName args} {
	if {[my MakeTypecastWrapper $methodName]} {
	    tailcall my $methodName {*}$args
	}
	next $methodName {*}$args
    }
    unexport unknown

    # Builder:MakeTypecastWrapper --
    #
    #	Determine whether the given non-existing method can be constructed by
    #	wrapping around a method with wider types and injecting operations
    #	such as casting and temporary string construction. For example, we can
    #	widen 'add(INT,DOUBLE)' to 'add(DOUBLE,DOUBLE)' by insertion of a
    #	cast-to-double on the first argument.
    #
    #	Expects to only ever be called from 'unknown'.
    #
    # Parameters:
    #	signature -
    #		The signature of the method that was desired. The signature is
    #		the name of the method; for the methods that we are interested
    #		in, they follow the pattern 'prefix(type,...,type)', where the
    #		prefix is the same as an *existing* method that follows the
    #		same pattern, except with types that we can automatically
    #		widen to. If it doesn't fit the pattern, or if there's no
    #		wider method definition, this method will refuse to generate
    #		code and will cause 'unknown' to fall through to the default
    #		error handling code (i.e., generating an error message).
    #
    # Results:
    #	Boolean that indicates whether we created the method with the
    #	requested signature.
    #
    # Side effects:
    # 	May create a method on the current object.

    # FIXME This method is really wrong when dealing with multiple possible
    # conversions (INT=>DOUBLE and INT=>STRING and DOUBLE=>STRING).
    method MakeTypecastWrapper {signature} {
	# This method inserts casts to lift INT to DOUBLE as necessary,
	# provided there is a way of generating the instruction with
	# DOUBLE in the first place.
	if {![regexp {^([^()]+)\(([\w,]+)\)$} $signature -> name types]} {
	    return 0
	}
	set n ${name}([regsub -all {(?!STRING)\w+} $types DOUBLE])
	if {$n in [info class methods [self class]]} {
	    set num [llength [set types [split $types ,]]]
	    set formals [lindex [info class definition [self class] $n] 0]
	    set body "my $n"
	    foreach t $types f [lrange $formals 0 [expr {$num-1}]] {
		if {$t eq "DOUBLE"} {
		    append body { $} [lindex $f 0]
		} else {
		    append body { [my cast(DOUBLE) $} [lindex $f 0] { cast]}
		}
	    }
	    foreach f [lrange $formals $num end] {
		append body { $} [lindex $f 0]
	    }
	    oo::objdefine [self] method $signature $formals $body
	    return 1
	}

	set n ${name}([regsub -all {\w+} $types STRING])
	if {$n in [info class methods [self class]]} {
	    set num [llength [set types [split $types ,]]]
	    set formals [lindex [info class definition [self class] $n] 0]
	    set body "set {string casts} {}"
	    foreach t $types f [lrange $formals 0 [expr {$num-1}]] {
		if {$t ne "STRING"} {
		    set t [string map {{ } _} $t]
		    set var [lindex $f 0]
		    append body ";" [string trim [subst -nocommands {
			lappend {string casts} [set $var [my stringify($t) $$var]]
		    }]]
		}
	    }
	    append body ";set result \[my $n"
	    foreach f $formals {
		append body { $} [lindex $f 0]
	    }
	    append body "\];" {
		foreach cast ${string casts} {my dropReference $cast}
		return $result
	    }
	    oo::objdefine [self] method $signature $formals $body
	    return 1
	}

	return 0
    }

    # Builder:packInt32 --
    #
    #	Generate code to convert an int32 to an INT.
    #
    # Parameters:
    #	value -	The 32-bit integer LLVM value reference.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	The INT LLVM value reference.

    method packInt32 {value {name ""}} {
	my insert [my insert [GetUndef [Type INT]] \
		       [Const ${::LLVM::INT.type.32bit}] \
		       ${::LLVM::INT.type.index}] \
	    $value ${::LLVM::INT.32.index} $name
    }

    # Builder:packInt64 --
    #
    #	Generate code to convert an int64 to an INT.
    #
    # Parameters:
    #	value -	The 64-bit integer LLVM value reference.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	The INT LLVM value reference.

    method packInt64 {value {name ""}} {
	my insert [my insert [GetUndef [Type INT]] \
		       [Const ${::LLVM::INT.type.64bit}] \
		       ${::LLVM::INT.type.index}] \
	    $value ${::LLVM::INT.64.index} $name
    }

    # Builder:isInt32 --
    #
    #	Generate code to test if an INT holds an int32.
    #
    # Parameters:
    #	INT -	The INT LLVM value reference.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A boolean (int1) LLVM value reference.

    method isInt32 {INT {name ""}} {
	my eq [my extract $INT ${::LLVM::INT.type.index}] \
	    [Const ${::LLVM::INT.type.32bit}] $name
    }

    # Builder:int.32 --
    #
    #	Generate code to extract the int32 from an INT. Caller MUST guarantee
    #	that the size was tested for first.
    #
    # Parameters:
    #	INT -	The INT LLVM value reference.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int32 LLVM value reference.

    method int.32 {INT {name ""}} {
	my extract $INT ${::LLVM::INT.32.index} $name
    }

    # Builder:int.64 --
    #
    #	Generate code to extract the int64 from an INT. Caller MUST guarantee
    #	that the size was tested for first.
    #
    # Parameters:
    #	INT -	The INT LLVM value reference.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int64 LLVM value reference.

    method int.64 {INT {name ""}} {
	my extract $INT ${::LLVM::INT.64.index} $name
    }

    # Builder:in32range --
    #
    #	Generate code to test if an int64 value will fit exactly in an int32.
    #
    # Parameters:
    #	int -	The int64 LLVM value reference.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A boolean (int1) LLVM value reference.

    method in32range {int {name ""}} {
	my select [my ge $int [Const -0x80000000 int64]] \
	    [my le $int [Const 0x7fffffff int64]] [Const true bool] $name
    }

    # Builder:add --
    #
    #	Generate code to add two integers of the same bit width.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method add {left right {name ""}} {
	BuildAdd $b $left $right $name
    }

    # Builder:add(INT,INT) --
    #
    #	Generate code to add two INTs. Quadcode implementation ('add').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method add(INT,INT) {left right {name ""}} {
	my call ${tcl.add} [list $left $right] $name
    }

    # Builder:add(DOUBLE,DOUBLE) --
    #
    #	Generate code to add two DOUBLEs. Quadcode implementation ('add').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method add(DOUBLE,DOUBLE) {left right {name ""}} {
	BuildFAdd $b $left $right $name
    }

    # Builder:addReference --
    #
    #	Generate code to increment the reference count of a value.
    #
    # Parameters:
    #	value -	The STRING/etc. LLVM value reference for the operand.
    #
    # Results:
    #	None.

    method addReference {value} {
	my call ${tcl.addReference} [list $value] ""
	return
    }

    # Builder:and --
    #
    #	Generate code to compute the bitwise-and of two integers of the same
    #	bit width.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method and {left right {name ""}} {
	BuildAnd $b $left $right $name
    }

    # Builder:alloc --
    #
    #	Generate code to allocate a writable memory location on the stack.
    #
    # Parameters:
    #	type -	The type of the memory location to allocate.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A pointer to the location as an LLVM value reference.

    method alloc {type {name ""}} {
	BuildAlloca $b $type $name
    }

    method appendString(STRING) {value buffer} {
	my call ${tcl.append.string} [list $buffer $value] ""
	return
    }

    # Builder:arrayAlloc --
    #
    #	Generate code to allocate a contiguous array of memory cells on the
    #	stack.
    #
    # Parameters:
    #	type -	The type of each of the memory cells.
    #	size -	The number of cells to create as an int[X] LLVM value
    #		reference. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A pointer to the first cell in the array.

    method arrayAlloc {type size {name ""}} {
	BuildArrayAlloca $b $type $size $name
    }

    # Builder:assume --
    #
    #	Generate code to tell LLVM that a particular boolean expression is
    #	true. Used to optimize reference count management, among other things.
    #
    # Parameters:
    #	fact -	The int1 LLVM value reference for the fact that is being told
    #		to the LLVM engine.
    #
    # Results:
    #	None.

    method assume {fact} {
	catch {
	    if {![info exist ::env(NOASSERTS)]} {
		my call [$module intrinsic assume] [list $fact]
	    }
	}
    }

    # Builder:bitand(INT,INT) --
    #
    #	Generate code to create the bitwise-and of two INTs. Quadcode
    #	implementation ('bitand').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method bitand(INT,INT) {left right {name ""}} {
	my call ${tcl.and} [list $left $right] $name
    }

    # Builder:bitnot(INT) --
    #
    #	Generate code to create the bitwise-not of an INT. Quadcode
    #	implementation ('bitnot').
    #
    # Parameters:
    #	value -	The INT LLVM value reference for the operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method bitnot(INT) {value {name ""}} {
	my call ${tcl.not} [list $value] $name
    }

    # Builder:bitor(INT,INT) --
    #
    #	Generate code to create the bitwise-or of two INTs. Quadcode
    #	implementation ('bitor').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method bitor(INT,INT) {left right {name ""}} {
	my call ${tcl.or} [list $left $right] $name
    }

    # Builder:bitxor(INT,INT) --
    #
    #	Generate code to create the bitwise exclusive-or of two INTs.
    #	Quadcode implementation ('bitxor').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method bitxor(INT,INT) {left right {name ""}} {
	my call ${tcl.xor} [list $left $right] $name
    }

    method br target {
	BuildBr $b [$target ref]
    }

    # Builder:call --
    #
    #	Generate code to call a function. Note that the function might be an
    #	inlining candidate, and might be a candidate for being tail-called.
    #
    # Parameters:
    #	function -
    #		The LLVM value reference to the function. Note that this is
    #		NOT the wrapped reference.
    #	arguments -
    #		The Tcl list of LLVM value references to pass as arguments to
    #		the function. These *must* match the argument types of the
    #		function or LLVM will panic.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An LLVM value reference if the function returns anything. The type
    #	depends on what the function returns.

    method call {function arguments {name ""}} {
	BuildCall $b $function $arguments $name
    }

    method cast(BOOLEAN) {value {name ""}} {
	my packInt32 [BuildIntCast $b $value [Type int] $name]
    }

    method cast(DOUBLE) {value {name ""}} {
	BuildSIToFP $b [my getInt64 $value] [Type DOUBLE] $name
    }

    method cast(INT) {value {name ""}} {
	set val [BuildFPToSI $b $value [Type int64] ""]
	if {$::tcl_platform(wordSize) == 4} {
	    my select [my in32range $val] \
		[my packInt32 [my cast(int) $val]] [my packInt64 $val] \
		$name
	} else {
	    my packInt64 $val $name
	}
    }

    method cast(bool) {value {name ""}} {
	BuildICmp $b LLVMIntNE [my getInt64 $value] [Const 0 int64] $name
    }

    method cast(int) {value {name ""}} {
	BuildIntCast $b $value [Type int] $name
    }

    method cast(int64) {value {name ""}} {
	BuildIntCast $b $value [Type int64] $name
    }

    method cast(ptr) {value type {name ""}} {
	BuildPointerCast $b $value [Type $type*] $name
    }

    method cast(uint) {value {name ""}} {
	BuildZExtOrBitCast $b $value [Type int] $name
    }

    method condBr(INT) {cond true false} {
	set realcond [BuildICmp $b LLVMIntNE [my getInt64 $cond] \
			  [Const 0 int64] ""]
	BuildCondBr $b $realcond [$true ref] [$false ref]
    }

    method condBr {cond true false} {
	BuildCondBr $b $cond [$true ref] [$false ref]
    }

    method constString {content {name "string.constant"}} {
	BuildGlobalStringPtr $b $content $name
    }

    method copy {value {name ""}} {
	return $value
    }

    # Builder:diff --
    #
    #	Generate code to compute the difference between two pointers.
    #
    # Parameters:
    #	left -	The pointer LLVM value reference for the left operand.
    #	right -	The pointer LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int64 LLVM value reference.

    method diff {ptr1 ptr2 {name ""}} {
	BuildPtrDiff $b $ptr1 $ptr2 $name
    }

    # Builder:div(INT,INT) --
    #
    #	Generate code to divide two INTs. Quadcode implementation ('div').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method div(INT,INT) {left right {name ""}} {
	my call ${tcl.div} [list $left $right] $name
    }

    # Builder:div(DOUBLE,DOUBLE) --
    #
    #	Generate code to divide two DOUBLEs. Quadcode implementation ('div').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method div(DOUBLE,DOUBLE) {left right {name ""}} {
	BuildFDiv $b $left $right $name
    }

    method dropReference {value} {
	my call ${tcl.dropReference} [list $value] ""
	return
    }

    # Builder:eq --
    #
    #	Generate code to compare two integers of the same bit width *or* two
    #	pointers for equality.
    #
    # Parameters:
    #	left -	The int[X] or pointer LLVM value reference for the left
    #		operand. (X is any width supported by LLVM.)
    #	right -	The int[X] or pointer LLVM value reference for the right
    #		operand. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method eq {left right {name ""}} {
	BuildICmp $b LLVMIntEQ $left $right $name
    }

    # Builder:eq(INT,INT) --
    #
    #	Generate code to compare two INTs for equality. Quadcode
    #	implementation ('eq').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method eq(INT,INT) {left right {name ""}} {
	my call ${tcl.eq} [list $left $right] $name
    }

    # Builder:eq(DOUBLE,DOUBLE) --
    #
    #	Generate code to compare two DOUBLEs for equality. Quadcode
    #	implementation ('eq').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method eq(DOUBLE,DOUBLE) {left right {name ""}} {
	my cast(BOOLEAN) [BuildFCmp $b LLVMRealOEQ $left $right $name]
    }

    method eq(STRING,STRING) {left right {name ""}} {
	my streq(STRING,STRING) $left $right $name
    }

    # Builder:expon(INT,INT) --
    #
    #	Generate code to compute one INT raised to the exponent another INT
    #	(i.e., left**right).  Quadcode implementation ('expon').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method expon(INT,INT) {left right {name ""}} {
	my call ${tcl.ipow} [list $left $right] $name
    }

    # Builder:expon(DOUBLE,INT) --
    #
    #	Generate code to raise a DOUBLE to the power of an INT. Quadcode
    #	implementation ('expon').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method expon(DOUBLE,INT) {left right {name ""}} {
	my call ${tcl.powi} [list $left $right] $name
    }

    # Builder:expon(DOUBLE,DOUBLE) --
    #
    #	Generate code to raise a DOUBLE to the power of a DOUBLE. Quadcode
    #	implementation ('expon').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method expon(DOUBLE,DOUBLE) {left right {name ""}} {
	set pow [$module intrinsic pow [Type DOUBLE]]
	my call $pow [list $left $right] $name
    }

    # Builder:ge --
    #
    #	Generate code to compare two integers of the same bit width *or* two
    #	pointers to see if the first is greater or equal to the second.
    #
    # Parameters:
    #	left -	The int[X] or pointer LLVM value reference for the left
    #		operand. (X is any width supported by LLVM.)
    #	right -	The int[X] or pointer LLVM value reference for the right
    #		operand. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method ge {left right {name ""}} {
	BuildICmp $b LLVMIntSGE $left $right $name
    }

    # Builder:ge(INT,INT) --
    #
    #	Generate code to see if one INT is greater than or equal to another
    #	INT.  Quadcode implementation ('ge').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method ge(INT,INT) {left right {name ""}} {
	my call ${tcl.ge} [list $left $right] $name
    }

    # Builder:ge(DOUBLE,DOUBLE) --
    #
    #	Generate code to compare two DOUBLEs for being greater than or equal.
    #	Quadcode implementation ('eq').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method ge(DOUBLE,DOUBLE) {left right {name ""}} {
	my cast(BOOLEAN) [BuildFCmp $b LLVMRealOGE $left $right $name]
    }

    method ge(STRING,STRING) {left right {name ""}} {
	my ge [my call ${tcl.strcmp} [list $left $right] ""] [Const 0] $name
    }

    method getelementptr {var indices {name ""}} {
	BuildGEP $b $var $indices $name
    }

    method gep {var args} {
	BuildGEP $b $var [lmap idx $args {Const $idx}] ""
    }

    method dereference {var args} {
	BuildLoad $b [BuildGEP $b $var [lmap idx $args {Const $idx}] ""] ""
    }

    # Builder:gt --
    #
    #	Generate code to compare two integers of the same bit width *or* two
    #	pointers to see if the first is greater than the second.
    #
    # Parameters:
    #	left -	The int[X] or pointer LLVM value reference for the left
    #		operand. (X is any width supported by LLVM.)
    #	right -	The int[X] or pointer LLVM value reference for the right
    #		operand. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method gt {left right {name ""}} {
	BuildICmp $b LLVMIntSGT $left $right $name
    }

    # Builder:gt(INT,INT) --
    #
    #	Generate code to see if one INT is greater than another INT.  Quadcode
    #	implementation ('gt').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method gt(INT,INT) {left right {name ""}} {
	my call ${tcl.gt} [list $left $right] $name
    }

    # Builder:gt(DOUBLE,DOUBLE) --
    #
    #	Generate code to compare two DOUBLEs for the first being greater than
    #	the second. Quadcode implementation ('eq').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method gt(DOUBLE,DOUBLE) {left right {name ""}} {
	my cast(BOOLEAN) [BuildFCmp $b LLVMRealOGT $left $right $name]
    }

    method gt(STRING,STRING) {left right {name ""}} {
	my gt [my call ${tcl.strcmp} [list $left $right] ""] [Const 0] $name
    }

    method extract {structure index {name ""}} {
	BuildExtractValue $b $structure $index $name
    }

    method insert {structure element index {name ""}} {
	BuildInsertValue $b $structure $element $index $name
    }

    # Builder:le --
    #
    #	Generate code to compare two integers of the same bit width *or* two
    #	pointers to see if the first is less or equal to the second.
    #
    # Parameters:
    #	left -	The int[X] or pointer LLVM value reference for the left
    #		operand. (X is any width supported by LLVM.)
    #	right -	The int[X] or pointer LLVM value reference for the right
    #		operand. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method le {left right {name ""}} {
	BuildICmp $b LLVMIntSLE $left $right $name
    }

    # Builder:le(INT,INT) --
    #
    #	Generate code to see of one INT is less than or equal to another INT.
    #	Quadcode implementation ('le').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method le(INT,INT) {left right {name ""}} {
	my call ${tcl.le} [list $left $right] $name
    }

    # Builder:le(DOUBLE,DOUBLE) --
    #
    #	Generate code to compare two DOUBLEs for the first being less than or
    #	equal to the second. Quadcode implementation ('eq').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method le(DOUBLE,DOUBLE) {left right {name ""}} {
	my cast(BOOLEAN) [BuildFCmp $b LLVMRealOLE $left $right $name]
    }

    method le(STRING,STRING) {left right {name ""}} {
	my le [my call ${tcl.strcmp} [list $left $right] ""] [Const 0] $name
    }

    method load {var {name ""}} {
	BuildLoad $b $var $name
    }

    # Builder:lshift --
    #
    #	Generate code to shift an integer left.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method lshift {left right {name ""}} {
	BuildShl $b $left $right $name
    }

    # Builder:lshift(INT,INT) --
    #
    #	Generate code to shift an INT left (multiply by powers of 2). Quadcode
    #	implementation ('lshift').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method lshift(INT,INT) {left right {name ""}} {
	my call ${tcl.shl} [list $left $right] $name
    }

    # Builder:lt --
    #
    #	Generate code to compare two integers of the same bit width *or* two
    #	pointers to see if the first is less than the second.
    #
    # Parameters:
    #	left -	The int[X] or pointer LLVM value reference for the left
    #		operand. (X is any width supported by LLVM.)
    #	right -	The int[X] or pointer LLVM value reference for the right
    #		operand. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method lt {left right {name ""}} {
	BuildICmp $b LLVMIntSLT $left $right $name
    }

    # Builder:lt(INT,INT) --
    #
    #	Generate code to see if one INT is less than another INT. Quadcode
    #	implementation ('lt').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method lt(INT,INT) {left right {name ""}} {
	my call ${tcl.lt} [list $left $right] $name
    }

    # Builder:lt(DOUBLE,DOUBLE) --
    #
    #	Generate code to compare two DOUBLEs for the first being less than the
    #	second. Quadcode implementation ('eq').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method lt(DOUBLE,DOUBLE) {left right {name ""}} {
	my cast(BOOLEAN) [BuildFCmp $b LLVMRealOLT $left $right $name]
    }

    method lt(STRING,STRING) {left right {name ""}} {
	my lt [my call ${tcl.strcmp} [list $left $right] ""] [Const 0] $name
    }

    # Builder:mod(INT,INT) --
    #
    #	Generate code to compute the mod of one INT by another INT. Quadcode
    #	implementation ('mod').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method mod(INT,INT) {left right {name ""}} {
	my call ${tcl.mod} [list $left $right] $name
    }

    # Builder:mult --
    #
    #	Generate code to multiply two integers of the same bit width.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method mult {left right {name ""}} {
	BuildMul $b $left $right $name
    }

    # Builder:mult(INT,INT) --
    #
    #	Generate code to multiply two INTs. Quadcode implementation ('mult').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method mult(INT,INT) {left right {name ""}} {
	my call ${tcl.mul} [list $left $right] $name
    }

    # Builder:add(DOUBLE,DOUBLE) --
    #
    #	Generate code to multiply two DOUBLEs. Quadcode implementation
    #	('mult').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method mult(DOUBLE,DOUBLE) {left right {name ""}} {
	BuildFMul $b $left $right $name
    }

    # Builder:neq --
    #
    #	Generate code to compare two integers of the same bit width *or* two
    #	pointers to see if the first is not equal to the second.
    #
    # Parameters:
    #	left -	The int[X] or pointer LLVM value reference for the left
    #		operand. (X is any width supported by LLVM.)
    #	right -	The int[X] or pointer LLVM value reference for the right
    #		operand. (X is the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method neq {left right {name ""}} {
	BuildICmp $b LLVMIntNE $left $right $name
    }

    # Builder:neq(INT,INT) --
    #
    #	Generate code to see if two INTs are not equal. Quadcode
    #	implementation ('neq').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method neq(INT,INT) {left right {name ""}} {
	my call ${tcl.ne} [list $left $right] $name
    }

    # Builder:neq(DOUBLE,DOUBLE) --
    #
    #	Generate code to compare two DOUBLEs for inequalty. Quadcode
    #	implementation ('eq').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method neq(DOUBLE,DOUBLE) {left right {name ""}} {
	my cast(BOOLEAN) [BuildFCmp $b LLVMRealONE $left $right $name]
    }

    method neq(STRING,STRING) {left right {name ""}} {
	my not(INT) [my streq(STRING,STRING) $left $right] $name
    }

    # Builder:nonnull --
    #
    #	Generate code to test if a pointer is not null.
    #
    # Parameters:
    #	value -	The pointer LLVM value reference for the operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method nonnull {value {name ""}} {
	BuildIsNotNull $b $value $name
    }

    # Builder:not --
    #
    #	Generate code to compute the logical not of an int1.
    #
    # Parameters:
    #	value -	The int1 LLVM value reference for the left operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int1 LLVM value reference.

    method not {value {name ""}} {
	my select $value [Const false bool] [Const true bool]
    }

    # Builder:not(INT) --
    #
    #	Generate code to create the logical not of a DOUBLE. Quadcode
    #	implementation ('not').
    #
    # Parameters:
    #	value -	The DOUBLE LLVM value reference for the operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method not(DOUBLE) {value {name ""}} {
	set cond [my eq(DOUBLE,DOUBLE) $value [Const 0.0 double]]
	set realcond [BuildICmp $b LLVMIntNE [my getInt64 $cond] \
			  [Const 0 int64] ""]
	my select $realcond \
	    [my packInt32 [Const 1]] [my packInt32 [Const 0]] $name
    }

    # Builder:not(INT) --
    #
    #	Generate code to create the logical not of an INT. Quadcode
    #	implementation ('not').
    #
    # Parameters:
    #	value -	The INT LLVM value reference for the operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method not(INT) {value {name ""}} {
	set cond [my eq(INT,INT) $value [my packInt32 [Const 0]]]
	set realcond [BuildICmp $b LLVMIntNE [my getInt64 $cond] \
			  [Const 0 int64] ""]
	my select $realcond \
	    [my packInt32 [Const 1]] [my packInt32 [Const 0]] $name
    }

    # Builder:or --
    #
    #	Generate code to compute the bitwise-or of two integers of the same
    #	bit width.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method or {left right {name ""}} {
	BuildOr $b $left $right $name
    }

    method pointerCast {value type {name ""}} {
	BuildPointerCast $b $value $type $name
    }

    method ret {{value ""}} {
	if {$value ne ""} {
	    BuildRet $b $value
	} else {
	    BuildRetVoid $b
	}
    }

    # Builder:rshift --
    #
    #	Generate code to shift an integer right.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method rshift {left right {name ""}} {
	BuildAShr $b $left $right $name
    }

    # Builder:rshift(INT,INT) --
    #
    #	Generate code to shift an INT right (divide by powers of 2). Quadcode
    #	implementation ('rshift').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method rshift(INT,INT) {left right {name ""}} {
	my call ${tcl.shr} [list $left $right] $name
    }

    method select {condition ifTrue ifFalse {name ""}} {
	BuildSelect $b $condition $ifTrue $ifFalse $name
    }

    method store {value var} {
	BuildStore $b $value $var
    }

    # WARNING these allocate memory; caller must manage
    method stringify(DOUBLE) {value {name ""}} {
	my call ${tcl.stringify.double} [list $value] $name
    }

    method stringify(INT) {value {name ""}} {
	my call ${tcl.stringify.int} [list $value] $name
    }

    method strcase(STRING,INT) {value kind {name ""}} {
	my call ${tcl.strcase} [list $value [my getInt32 $kind]] $name
    }

    method strclass(STRING,INT) {value class {name ""}} {
	my call ${tcl.strclass} [list $value [my getInt32 $class]] $name
    }

    method strcmp(STRING,STRING) {left right {name ""}} {
	set val [my call ${tcl.strcmp} [list $left $right]]
	my select [my lt $val [Const 0]] [my packInt32 [Const -1]] [
		my select [my gt $val [Const 0]] [my packInt32 [Const 1]] \
			[my packInt32 [Const 0]]] $name
    }

    method streq(STRING,STRING) {left right {name ""}} {
	my call ${tcl.streq} [list $left $right] $name
    }

    method strfind(STRING,STRING) {needle haystack {name ""}} {
	my call ${tcl.strfind.fwd} [list $needle $haystack] $name
    }

    method strindex(STRING,INT) {str idx {name ""}} {
	my call ${tcl.stridx} [list $str $idx] $name
    }

    method strlen(STRING) {value {name ""}} {
	my call ${tcl.strlen} [list $value] $name
    }

    method strmap(STRING,STRING,STRING) {source target string {name ""}} {
	my call ${tcl.strmap} [list $source $target $string] $name
    }

    method strmatch(INT,STRING,STRING) {flag pattern string {name ""}} {
	my call ${tcl.strmatch} [list $flag $pattern $string] $name
    }

    method strrange(STRING,INT,INT) {str from to {name ""}} {
	my call ${tcl.strrange} [list $str $from $to] $name
    }

    method strreplace(STRING,INT,INT,STRING) {str from to substr {name ""}} {
	my call ${tcl.strreplace} [list $str $from $to $substr] $name
    }

    method strrfind(STRING,STRING) {needle haystack {name ""}} {
	my call ${tcl.strfind.rev} [list $needle $haystack] $name
    }

    method strtrim(STRING,STRING,INT) {str chars which {name ""}} {
	my call ${tcl.strtrim} [list $str $chars [my getInt32 $which]] $name
    }

    method switch {value else args} {
	# Type check the args
	if {![llength $args]} {error "what, no arms?"}
	foreach {case target} $args {incr case 0;$target ref}
	set s [BuildSwitch $b $value [$else ref] [expr {[llength $args] / 2}]]
	foreach {case target} $args {
	    AddCase $s [ConstInt [TypeOf $value] $case 1] [$target ref]
	}
	return $s
    }

    # Builder:sub --
    #
    #	Generate code to subtract two integers of the same bit width.
    #
    # Parameters:
    #	left -	The int[X] LLVM value reference for the left operand. (X is
    #		any width supported by LLVM.)
    #	right -	The int[X] LLVM value reference for the right operand. (X is
    #		the same as for the 'left' parameter.)
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An int[X] LLVM value reference.

    method sub {left right {name ""}} {
	BuildSub $b $left $right $name
    }

    # Builder:sub(INT,INT) --
    #
    #	Generate code to subtract two INTs. Quadcode implementation ('sub').
    #
    # Parameters:
    #	left -	The INT LLVM value reference for the left operand.
    #	right -	The INT LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method sub(INT,INT) {left right {name ""}} {
	my call ${tcl.sub} [list $left $right] $name
    }

    # Builder:sub(DOUBLE,DOUBLE) --
    #
    #	Generate code to subtract two DOUBLEs. Quadcode implementation
    #	('sub').
    #
    # Parameters:
    #	left -	The DOUBLE LLVM value reference for the left operand.
    #	right -	The DOUBLE LLVM value reference for the right operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method sub(DOUBLE,DOUBLE) {left right {name ""}} {
	BuildFSub $b $left $right $name
    }

    # Builder:uminus(INT) --
    #
    #	Generate code to create the negation of an INT. Quadcode
    #	implementation ('uminus').
    #
    # Parameters:
    #	value -	The INT LLVM value reference for the operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An INT LLVM value reference.

    method uminus(INT) {value {name ""}} {
	my call ${tcl.neg} [list $value] $name
    }

    # Builder:uminus(DOUBLE) --
    #
    #	Generate code to create the negation of a DOUBLE. Quadcode
    #	implementation ('uminus').
    #
    # Parameters:
    #	value -	The DOUBLE LLVM value reference for the operand.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	A DOUBLE LLVM value reference.

    method uminus(DOUBLE) {value {name ""}} {
	BuildFNeg $b $value $name
    }

    method unshare(STRING) {value {name ""}} {
	my call ${tcl.unshare} [list $value] $name
    }

    method unshareCopy(STRING) {value {name ""}} {
	my call ${tcl.unshare.copy} [list $value] $name
    }

    method phi {values sources {name ""}} {
	set type [TypeOf [lindex $values 1]]
	if {![llength $values]} {error "what, no origins?"}
	if {[llength $values] != [llength $sources]} {
	    error "values and sources must be same length"
	}
	set phi [BuildPhi $b $type $name]
	foreach value $values block $sources {
	    AddIncoming $phi $value [$block ref]
	}
	return $phi
    }
}

# Local Variables:
# mode: tcl
# fill-column: 78
# End:
