view genasm.rhope @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -0400
parents 31f8182f3433
children 43cc42df26cc
line wrap: on
line source

//Import extendlib.rhope
Import backendutils.rhope

Blueprint Registers
{
	Names
	Can Data
	Can Pointer
	Available?
	Need Save
	Max Size
}

Set Yes[in:out]
{
	out <- Yes
}

_Flip[dest,val,index:out]
{
	out <- [dest]Set[val,index]
}
Flip[list,dest:out]
{
	out <- Fold["_Flip", dest, list]
}

Registers[names, data, pointer, need save, max size:out]
{
	out <- [[[[[[Build["Registers"]
	]Names << [names]
	]Can Data << [data]
	]Can Pointer << [pointer]
	]Available? << [ Map[names, "Set Yes"] ]
	]Need Save << [ Flip[need save, ()] ]
	]Max Size <<[max size]
}

Name@Registers[regs,num:out]
{
	out <- [[regs]Names >>]Index[num]
}

Allocate Helper@Registers[regs, try, current:found, not found]
{
	reg <- [try]Index[current]
	If[[[regs]Available? >>]Index[reg]]
	{
		found <- Val[reg]
	}{
		[try]Next[current]
		{
			found, not found <- [regs]Allocate Helper[try, ~]
		}{
			not found <- Yes
		}
	}
}

Allocate Reg@Registers[regs,try:next regs,found,need save?,not found]
{
	[try]First
	{
		found, not found <- [regs]Allocate Helper[try, ~]
		{
			next regs <- [regs]Available? << [ [[regs]Available? >>]Set[~, No] ]
			[[regs]Need Save >>]Index[~]
			{
				need save? <- Yes
			}{
				need save? <- No
			}
		}
	}{
		not found <- Yes
	}
}

Free Reg@Registers[regs,num:out]
{
	out <- [regs]Available? <<[ [[regs]Available? >>]Set[num, Yes] ]
}

Processor Reg[func,type:next func,num,not found]
{
	regs <- [func]Registers >>
	If[[type] = ["pointer"]]
	{
		source <- [regs]Can Pointer >>
	}{
		source <- [regs]Can Data >>
	}
	next regs, reg num, need save?, not found <- [regs]Allocate Reg[source] {}
	{
		If[need save?]
		{
			next func <- [[func]Need Save << [ [[func]Need Save >>]Set[reg num, Yes] ]
			]Registers << [next regs]
		}{
			next func <- [func]Registers << [next regs]
		}
		num <- Val[reg num]
	}
}

Processor Free Reg[func,num:out func]
{
	out func <- [func]Registers <<[  [[func]Registers >>]Free Reg[num] ]
}

Processor Allocate[func,name,size,type:out func,out]
{
	regs <- [func]Registers >>
	If[[type] = ["pointer"]]
	{
		alloc size <- [func]Pointer Size
	}{
		alloc size <- size
	}
	If[[alloc size] > [[regs]Max Size >>]] {
			stack alloc <- Val[alloc size]
	}{
		next func <- [func]Processor Reg[type] {}
		{
			location <- Register[~, alloc size]
		}{
			stack alloc <- Val[alloc size]
		}
	}
	Val[stack alloc]
	{
		next func, location <- [func]Allocate Stack[alloc size]
	}
	out func <- [next func]Variables <<[ [[next func]Variables >>]Set[name, location] ]
	out <- Val[location]
}

Blueprint Register
{
	Number
	Value Size
}
Register[num,size:out]
{
	If[[size] = [3]]
	{
		value size <- 4
	}{
		value size <- size
	}
	out <- [[Build["Register"]]Number <<[num]]Value Size <<[value size]
}

In Memory?@Register[reg:out]
{
	out <- No
}

=@Register[reg,other:out]
{
	,out <- If[[Type Of[reg]] = [Type Of[other]]]
	{
		out <- [[reg]Number >>] = [[other]Number >>]
	}
}

Op ASM@Register[reg,func,regs,extra offset:out]
{
	out <- [regs]Index[ [reg]Number >> ]
}

Size@Register[reg:out]
{
	out <- [reg]Value Size >>
}

Blueprint Immediate
{
	Value
}

Immediate[val:out]
{
	out <- [Build["Immediate"]]Value <<[val]
}

In Memory?@Immediate[val:out]
{
	out <- No
}

=@Immediate[val,other:out]
{
	,out <- If[[Type Of[val]] = [Type Of[other]]]
	{
		out <- [[val]Value >>] = [[other]Value >>]
	}
}

Op ASM@Immediate[val,func,regs,extra offset:out]
{
	out <- [val]Value >>
}

Size@Immediate[val:out]
{
	out <- 4
}

Blueprint None
{
	Dummy
}

None[:out]
{
	out <- Build["None"]
}

In Memory?@None[none:out]
{
	out <- No
}

Op ASM@None[none,func,regs,extra offset:out]
{
	out <- ""
}

Size@None[none:out]
{
	out <- 0
}

Blueprint Stack Location
{
	Offset
	Size
}

Stack Location[offset,size:out]
{
	out <- [[Build["Stack Location"]]Offset <<[offset]]Size <<[size]
}

In Memory?@Stack Location[location:out]
{
	out <- Yes
}

=@Stack Location[loc,other:out]
{
	,out <- If[[Type Of[loc]] = [Type Of[other]]]
	{
		out <- [[loc]Offset >>] = [[other]Offset >>]
	}
}

Op ASM@Stack Location[loc,func,regs,extra offset:out]
{
	offset <- [[[func]Stack Size >>] - [[loc]Offset >>]] - [[loc]Size >>]
	If[[offset] > [0]]
	{
		toffset <- ["+"]Append[offset]
	}{
		toffset <- ""
	}
	out <- [["[esp"]Append[toffset]]Append["]"]
}

Size@Stack Location[loc:out]
{
	out <- [loc]Size >>
}

Blueprint Pointer
{
	Base
	Offset
	Target Size
}

Pointer[base,offset,size:out]
{
	out <- [[[Build["Pointer"]]Base <<[base]]Offset <<[offset]]Target Size <<[size]
}

In Memory?@Pointer[location:out]
{
	out <- Yes
}

=@Pointer[pointer,other:out]
{
	,out <- If[[Type Of[loc]] = [Type Of[other]]]
	{
		out <- [[loc]Storage >>] = [[other]Storage >>]
	}
}

Op ASM@Pointer[pointer,func,regs,extra offset:out]
{
	If[[Type Of[ [pointer]Offset >> ]] = ["None"]]
	{
		out <- [["["]Append[ [[pointer]Base >>]Op ASM[func,regs,extra offset] ]]Append["]"]
	}{
		out <- [[[["["
			]Append[ [[pointer]Base >>]Op ASM[func,regs,extra offset] ]
			]Append["+"]
			]Append[ [[pointer]Offset >>]Op ASM[func,regs,extra offset] ]
			]Append["]"]
	}
}

Size@Pointer[pointer:out]
{
	out <- [pointer]Target Size >>
}

Blueprint X86 Instruction
{
	Name
	Op1
	Op2
	Width
	Extra Offset
}

X86 Instruction[name, op1, op2, width:out]
{
	out <- [[[[[Build["X86 Instruction"]]Name << [name]]Op1 << [op1]]Op2 <<[op2]]Width <<[width]]Extra Offset <<[0]
}

CAppend[left,right:out]
{
	If[[right] = [""]]
	{
		out <- ""
	}{
		out <- [left]Append[right]
	}
}

Inst ASM@X86 Instruction[inst,func:out]
{
	If[[[inst]Width >>] = [4]]
	{
		regs <- ("eax","ecx","edx","ebx","esi","edi","esp")
	}{
		If[[[inst]Width >>] = [2]]
		{
			regs <- ("ax","cx","dx","bx","si","di")
		}{
			regs <- ("al","cl","dl","bl","si","di")
		}
	}
	out <- [[[inst]Name >>
	]Append[ [" "]CAppend[[[inst]Op1>>]Op ASM[func, regs, [inst]Extra Offset >>]] ]
	]Append[ [", "]CAppend[[[inst]Op2>>]Op ASM[func, regs, [inst]Extra Offset >>]] ]
}

Blueprint X86 Function
{
	Name
	Registers
	Variables
	Scratch
	Need Save
	Free Stack Locations
	Stack Size
	Param Size
	Temp Stack
	Convention
	Instructions
}

X86 Function[name,params,convention:out]
{
	[[[[[[[[[Build["X86 Function"]
	]Name << [name]
	]Registers << [Registers[("eax","ecx","edx","ebx","esi","edi"), (0,1,2,3,4,5), (0,1,2,3,4,5), (3,4,5), 4]]
	]Variables  <<[New@Dictionary[]]
	]Need Save <<[()]
	]Free Stack Locations <<[()]
	]Stack Size <<[0]
	]Instructions <<[()]
	]Convention <<[convention]
	]Alloc Params[params, convention]
	{
		out <- [~]Param Size <<[ [~]Stack Size >> ]
	}
}

Pointer Size@X86 Function[func:out]
{
	out <- 4
}

Param Helper@X86 Function[func, param:out]
{
	,loc <- [func]Allocate Stack[4]
	{
		out <- [~]Variables << [ [[~]Variables >>]Set[param, loc] ]
	}
}

Alloc Params@X86 Function[func,params,convention:out]
{
	If[[convention] = ["fastcall"]]
	{
		[params]Index[0]
		{
				next func <- [[func]Registers <<[ [[func]Registers >>]Available? <<[ [[[func]Registers >>]Available? >>]Set[1, No] ]]
				]Variables <<[ [[func]Variables >>]Set[~, Register[1,4]] ]
				[params]Index[1]
				{
					next func2 <- [[next func]Registers <<[ [[next func]Registers >>]Available? <<[ [[[next func]Registers >>]Available? >>]Set[2, No] ]]
					]Variables <<[ [[next func]Variables >>]Set[~, Register[2,4]] ]
					[params]Index[2]
					{
						out <- _Fold[params, 2, next func2, "Param Helper"]
					}{
						out <- Val[next func2]
					}
				}{
					out <- Val[next func]
				}
		}{
			out <- func
		}
	}{
		out <- Fold["Param Helper", func, params]
	}
}

Add Instruction@X86 Function[func, inst:out]
{
	out <- [func]Instructions << [ [[func]Instructions >>]Append[ [inst]Extra Offset <<[[func]Temp Stack >>] ] ]
}

Allocate Stack@X86 Function[func,size:func out,out]
{
	out <- Stack Location[[func]Stack Size >>, size]
	func out <- [func]Stack Size <<[ [[func]Stack Size >>]+[size] ]
}

Allocate Var@X86 Function[func,name,size,type:out func,out]
{
	out func, out <- Processor Allocate[func,name,size,type]
}

Resolve@X86 Function[func,op:out,out func]
{
	If[[Type Of[op]] = ["String"]]
	{
		out <- [[func]Variables >>]Index[op]
	}{
		out <- op
	}
}

Allocate Scratch@X86 Function[func,size:out func,scratch]
{
	out func,scratch <- Processor Reg[func,"data"] {} {}
	{
		//FIXME: need to use a reg that's not involved in the current op
		//FIXME: Also, might need two scratch regs and both might be in use
		,stack inc <- [func]Save Reg[0]
		{
			out func <- [~]Scratch << [ [[~]Scratch >>]Set[0, Yes] ]
		}
	}
}

Free Scratch@X86 Function[func,scratch:out func]
{
	[[func]Scratch >>]Index[scratch]
	{
		[func]Restore Reg[scratch]
		{
			out func <- [~]Scratch << [ [[~]Scratch >>]Remove[scratch] ]
		}
	}{
		out func <- Processor Free Reg[func, scratch]
	}
	If[[scratch]Index[1]]
	{
		
	}{
		
	}
}

Classify Op@X86 Function[func,op:class]
{
	If[[op]In Memory?]
	{
		If[[Type Of[op]] = ["Pointer"]]
		{
			If[[[[op]Base >>]In Memory?] Or [[[op]Offset >>]In Memory?]]
			{
				class <- "u"
			}{
				class <- "m"
			}
		}{
			class <- "m"
		}
	}{
		class <- "r"
	}
}

RegMem2Op@X86 Function[func,dest,notdest,op,size:out]
{
	out <- [func]Add Instruction[X86 Instruction[op, dest, notdest, size]]
}

MemPointer2Op@X86 Function[func,dest,notdest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		out <- [[[~]Fetch[notdest,scratch]
			]Add Instruction[X86 Instruction[op, dest, scratch, size]]
			]Free Scratch[scratch]
	}
}

//Make sure to map this to both r, (m or r) -> m and r, (m or r) -> r
RegMemToNotPointer@X86 Function[func,source1,source2,dest,op,size:out]
{
	out <- [[func]Move[source2,dest]
		]Add Instruction[X86 Instruction[op, dest, source1, size]]
}

RegMemToPointer@X86 Function[func,source1,source2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		out <- [[[[~]Calculate Address[dest, scratch]
			]Move[source2, spointer]
			]Add Instruction[X86 Instruction[op, spointer, source1, size]]
			]Free Scratch[scratch]
	}
}

RegPointerToMem@X86 Function[func,source1,source2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		out <- [[[[~]Calculate Address[source2, scratch]
			]Move[spointer, dest]
			]Add Instruction[X86 Instruction[op, dest, source1, size]]
			]Free Scratch[scratch]
	}
}

RegPointerReg2Op@X86 Function[func,dest,notdest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		out <- [[[~]Calculate Address[notdest, scratch]
			]Add Instruction[X86 Instruction[op, dest, spointer, size]]
			]Free Scratch[scratch]
	}
}

RegPointerPointer2Op@X86 Function[func,dest,notdest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		out <- [[[~]Calculate Address[dest, scratch]
			]Add Instruction[X86 Instruction[op, spointer, notdest, size]]
			]Free Scratch[scratch]
	}
}

RegPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		,scratch2 <- [~]Allocate Scratch[size]
		{
			spointer2 <- Pointer[scratch2, None[], size]
			out <- [[[[[[~]Calculate Address[source2, scratch]
				]Calculate Address[dest, scratch2]
				]Move[spointer2, spointer]
				]Add Instruction[X86 Instruction[op, spointer2, source1, size]]
				]Free Scratch[scratch2]
				]Free Scratch[scratch]
		}
	}
}

//If source1, source2 and dest are all pointers with register offsets, allocating a scratch register could
//become a problem unless I let ebp be used as a scratch register. Should be doable as long as thread local
//variables properly report ebp as a used register. Alternatively, one register could be reserved for scratch
//usage
MemPointerToMem@X86 Function[func,source1,source2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		out <- [[[[~]Fetch[source2, scratch]
			]Add Instruction[X86 Instruction[op, scratch, source1, size]]
			]Move[scratch, dest]
			]Free Scratch[scratch]
	}
}

MemPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		,scratch2 <- [~]Allocate Scratch[size]
		{
			spointer2 <- Pointer[scratch2, None[], size]
			out <- [[[[[[~]Fetch[source2, scratch]
				]Add Instruction[X86 Instruction[op, scratch, source1, size]]
				]Calculate Address[dest, scratch2]
				]Move[scratch, spointer2]
				]Free Scratch[scratch2]
				]Free Scratch[scratch]
		}
	}
}

//This does almost the same thing as RegMemToNotPointer, depending on how I do the pattern matching I could maybe combine them
PointerMemToReg@X86 Function[func,source1,source2,dest,op,size:out]
{
	out <- [[func]Fetch[source1,dest]
		]Add Instruction[X86 Instruction[op, dest, source2, size]]
}

PointerPointer2Op@X86 Function[func,dest,notdest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		,scratch2 <- [~]Allocate Scratch[size]
		{
			out <- [[[[[[[~]Calculate Address[dest, scratch]
				]Fetch[notdest, scratch2]
				]Add Instruction[X86 Instruction[op, scratch, scratch2, size]]
				]Calculate Address[dest, scratch2]
				]Move[scratch, spointer2]
				]Free Scratch[scratch2]
				]Free Scratch[scratch]
		}
	}
}

PointerPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		,scratch2 <- [~]Allocate Scratch[size]
		{
			spointer2 <- Pointer[scratch2, None[], size]
			out <- [[[[[[[~]Fetch[source1, scratch]
				]Calculate Address[source2, scratch2]
				]Add Instruction[X86 Instruction[op, scratch, spointer2, size]]
				]Calculate Address[dest, scratch2]
				]Move[scratch, spointer2]
				]Free Scratch[scratch2]
				]Free Scratch[scratch]
		}
	}
}

PointerPointerToMem@X86 Function[func,source1,souce2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		out <- [[[[[~]Calculate Address[source1, scratch]
			]Move[dest, spointer]
			]Fetch[source2, scratch]
			]Add Instruction[X86 Instruction[op, dest, scratch, size]]
			]Free Scratch[scratch]
	}
}

PointerPointerToReg@X86 Function[func,source1,souce2,dest,op,size:out]
{
	,scratch <- [func]Allocate Scratch[size]
	{
		spointer <- Pointer[scratch, None[], size]
		out <- [[[[~]Fetch[source1, dest]
			]Calculate Address[source2, scratch]
			]Add Instruction[X86 Instruction[op, dest, scratch, size]]
			]Free Scratch[scratch]
	}
}

2Op Associative@X86 Function[func,psource1,psource2,pdest,name:out func]
{
	source1 <- [func]Resolve[psource1]
	source2 <- [func]Resolve[psource2]
	dest <- [func]Resolve[pdest]
	dest class <- [func]Classify Op[dest]
	width <- Min[Min[Min[[source1]Size,[source2]Size], [dest]Size], 4]
	swapper <- (1,0)
	sources <- [[()]Append[source1]Append[source2]
	[sources]Find[dest]
	{
		source <- [swapper]Index[~]
		source class <- [func]Classify Op[source]
		If[[dest class] = ["u"]]
		{
			If[[source class] = ["r"]]
			{
				out func <- [func]RegPointerPointer2Op[dest,source,name,width]
			}{
				out func <- [func]PointerPointer2Op[dest,source,name,width]
			}
		}{
			If[[dest class] = ["r"]]
			{
				If[[source class] = ["u"]]
				{
					out func <- [func]RegPointerReg2Op[dest,source,name,width]
				}{
					out func <- [func]RegMem2Op[dest,source,name,width]
				}
			}{
				If[[source class] = ["r"]]
				{
					out func <- [func]RegMem2Op[dest,source,name,width]
				}{
					out func <- [func]MemPointer2Op[dest,source,name,width]
				}
			}
		}
	}{
		sclasses <- Map[sources, ["Classify Op"]Set Input[0, func]]
		first <- [sources]Index[found index]
		other index <- [swapper]Index[found index]
		other <- [sources]Index[other index]
		other class <- [sclasses]Index[other index]
		found index <- [sclasses]Find["r"]
		{
			If[[other class] = ["u"]]
			{
				If[[dest class] = ["m"]]
				{
					out func <- [func]RegPointerToMem[first,other,dest,name,width]
				}{
					If[[dest class] = ["u"]]
					{
						out func <- [func]RegPointerToPointer[first,other,dest,name,width]
					}{
						out func <- [func]PointerMemToReg[other,first,dest,name,width]
					}
				}
			}{
				If[[dest class] = ["u"]]
				{
					out func <- [func]RegMemToPointer[first,other,dest,name,width]
				}{
					out func <- [func]RegMemToNotPointer[first,other,dest,name,width]
				}
			}
		}{
			found index <- [sclasses]Find["m"]
			{
				If[[dest class] = ["r"]]
				{
					out func <- [func]PointerMemToReg[other,first,dest,name,width]
				}{
					If[[dest class] = ["m"]]
					{
						out func <- [func]MemPointerToMem[first,other,dest,name,width]	
					}{
						out func <- [func]MemPointerToPointer[first,other,dest,name,width]
					}
				}
			}{
				If[[dest class] = ["r"]]
				{
					out func <- [func]PointerPointerToReg[first,other,dest,name,width]
				}{
					If[[dest class] = ["m"]]
					{
						out func <- [func]PointerPointerToMem[first,other,dest,name,width]
					}{
						out func <- [func]PointerPointerToPointer[first,other,dest,name,width]
					}
				}
			}
		}
	}
}

2Op@X86 Function[func,psource1,psource2,pdest,name:out func]
{
	source1 <- [func]Resolve[psource1]
	source2 <- [func]Resolve[psource2]
	dest <- [func]Resolve[pdest]
	width <- Min[Min[Min[[source1]Size,[source2]Size], [dest]Size], 4]
	If[[source1] = [dest]]
	{
		If[[[source1]In Memory?] And [[source2]In Memory?]]
		{
			,scratch, stack inc <- [func]Allocate Scratch[width]
			{
				out func <- [[[~]Add Instruction[X86 Instruction["mov", [scratch]Index[0], source2, width, stack inc]]
				]Add Instruction[X86 Instruction[name, source1, [scratch]Index[0], width, stack inc]]
				]Free Scratch[scratch]
			}
		}{
			out func <- [func]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
		}
	}{
		If[[dest]In Memory?]
		{
			If[[source2]In Memory?]
			{
				,scratch, stack inc <- [func]Allocate Scratch[width]
				{
					out func <- [[[[~]Add Instruction[X86 Instruction["mov", [scratch]Index[0], source1, width, stack inc]]
					]Add Instruction[X86 Instruction[name, [scratch]Index[0], source2, width, stack inc]]
					]Add Instruction[X86 Instruction["mov", dest, [scratch]Index[0], width, stack inc]]
					]Free Scratch[scratch]
				}
			}{
				out func <- [[func]Move[source1,dest]
				]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
			}
		}{
			out func <- [[func]Move[source1,dest]
			]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
		}
	}
}

Add@X86 Function[func,source1,source2,dest:out func]
{
	out func <- [func]2Op Associative[source1,source2,dest,"add"]
}

Sub@X86 Function[func,source1,source2,dest:out func]
{
	out func <- [func]2Op[source1,source2,dest,"sub"]
}

Move@X86 Function[func,psource,pdest:out func]
{
	source <- [func]Resolve[psource]
	dest <- [func]Resolve[pdest]
	out func <- [func]Add Instruction[X86 Instruction["mov", dest, source, 4]]
}

Instruction ASM[current,instruction,func:out]
{
	out <- [[[current]Append["\t"]]Append[ [instruction]Inst ASM[func] ]]Append["\n"]
}

Save Reg@X86 Function[func,reg:out]
{
	out <- [[func]Add Instruction[X86 Instruction["push", Register[reg, 4], None[], 4]]
	]Temp Stack << [ [[func]Temp Stack >>]+[4] ]
}

Prolog Save@X86 Function[func,junk,reg:out]
{
	out <- [[func]Add Instruction[X86 Instruction["push", Register[reg, 4], None[], 4]]
	]Stack Size << [ [[func]Stack Size >>]+[4] ]
}

Restore Reg@X86 Function[func,reg:out]
{
	out <- [[func]Add Instruction[X86 Instruction["pop", Register[reg, 4], None[], 4]]
	]Temp Stack << [ [[func]Temp Stack >>]-[4] ]
}

Epilogue Restore@X86 Function[func,junk,reg:out]
{
	out <- [func]Add Instruction[X86 Instruction["pop", Register[reg, 4], None[], 4]]
}

Finalize@X86 Function[func:out]
{
	alloc stack <- [[func]Stack Size >>] - [[func]Param Size >>]
	
	oldstream <- [func]Instructions >>
	
	If[[alloc stack] > [0]]
	{
		start <- [()]Append[X86 Instruction["sub", Register[6, 4],Immediate[alloc stack], Register[6, 4], 4], func]
	}{
		start <- ()
	}
	
	If[[[func]Convention >>] = ["cdecl"]]
	{
		If[ [alloc stack] > [0] ]
		{
			retparam <- Immediate[alloc stack]
		}{
			retparam <- None[]
		}
	}{
		retparam <- Immediate[[func]Stack Size >>]
	}
	
	[[func]Need Save >>]First
	{
		prolog <- Fold["Prolog Save", [func]Instructions << [start], [func]Need Save >>]
		out <- [Reverse Fold["Epilogue Restore", body, [func]Need Save >>]]Add Instruction[X86 Instruction["ret", retparam, None[], 4]]
	}{
		prolog <- [func]Instructions <<[start]
		out <- [body]Add Instruction[X86 Instruction["ret", retparam, None[], 4]]
	}
	
	body <- Fold["Add Instruction", prolog, oldstream]
}

Text@X86 Function[func:out]
{
	name line <- [Escape Rhope Name[[func]Name >>]
	]Append[":\n"]
	
	out <- Fold[["Instruction ASM"]Set Input[2, func], name line, [func]Instructions >>]
}