view genasm.rhope @ 89:5a195ee08eac

Fix memory leak and bug that was preventing First@Dictionary from working properly
author Mike Pavone <pavone@retrodev.com>
date Sat, 31 Jul 2010 00:19:15 -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 >>]
}