Mercurial > repos > rhope
view genasm.rhope @ 45:6420c35edb43
Fixed Linux makefile
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 30 Nov 2009 23:47:08 -0500 |
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 >>] }