I have a list of assembly instructions for an application, and I'd like to know what registers are free to use and what registers are in use at any index of the list.
How can I know when a register is being used and when it's freed (free to be used again) ? My goal is to reach the registers that are really free.
Here is my assumption to solve the problem, it might sound stupid as I have so limited knowledge of assembly.
Terminology : Read (source), Write (destination)
Does it solve the problem or make any sense? I'm open to other solutions as well.
Update after comments :
I see that JMPS/calls/conditional moves mess up all of this. Just to keep it safe (safe = free registers are really free), how about doing something like this: When I see any each jump/call/conditional move to the outside, I mark all registers as "being read" with a maximally pessimistic assumption as harold describes. I believe that I'd have safer results in that case, even though it won't be good as registers would be in busy state most of the time. Would you be able to agree that my results would be safe in that way?
Instructions:
Results :
Update 2
I'll instead split the application into basic blocks where each block represents a chunk of code between jumps (also conditional), calls and returns. The jump statements will be the end of the block. I'll then analyze the each block assuming that all of the registers are in use at the start. I'll probably miss lots of free registers, but when I get one, I'll know that that one is a really free one =)
Update 3
I'm still trying to improve the solution based on feedbacks (thanks harold).
I've read liveness analysis and as I understand it is recommended to analyze from the end of the application to the start. But I don't know the end of the application in a compiled assembly as mentioned as halt problem in the comments below, so I'll do the other way around with future branches.
may_continue_with
container that holds pointers to branches that it might continue with.Step 1 is easy, just a lot of work to actually implement (requires parsing of x86 machine code), there are some libraries that may help with that.
Step 2 is not as easy as you make it sound, because of control flow. Liveness analysis is, under the assumption that control flow is simple, is a well known problem. There are some extra problems in this case though.
switch
is compiled to a jump table. Actually it's not guaranteed that variable jumps will be interprocedural in the first place, you can probably mostly assume that.. I really don't know what to do about that.I'll then analyze the each block assuming that all of the registers are in use at the start.
That's a huge waste, which can easily be avoided by doing proper liveness analysis.