Closed ailrst closed 3 months ago
What's the point of mandating empty entry blocks? Doesn't this just make Procedure completely redundant as a node in the CFG? It doesn't really make sense to have both?
Rather than requiring it has no statements I think its more important to require it has no incoming (intraprocedural) jumps and only one outgoing jump.
Looking at removing Procedure from the CFG sounds like a good idea to me
We probably need to figure out more broadly how this should relate to non-returning procedures, and how they should be handled in the analyses (which generally do not account for their existence).
We probably need to figure out more broadly how this should relate to non-returning procedures, and how they should be handled in the analyses (which generally do not account for their existence).
I think to address this we might add a "Halt" statement, and just have an analysis determine for each procedure if all paths reach a halt statement or non-returning call. I don't think it necessarily interacts with this PR, because we don't want a single halt per-procedure in the same way we do returns for backwards analysis.
Otherwise, I think this PR is overcomplicated. I like having a fixed entry and return block, but the automatic rewriting of Returns into jumps to the exit block is unneccessary. It would make more sense to just have an analysis find all the returns and rewrite the procedure into a diamond shape, and have an invariant checker make sure this stays the case through subsequent transforms.
Is the idea that the 'halt' statement would follow a non-returning call? This could just be an 'assume false' then, but it could be made its own special type for ease of matching.
I agree that automatically rewriting returns like this is more complicated than necessary, and what you now suggest sounds like a better approach.
I think that creating a new Return class is a good idea though. It's worth making a simpler PR that just does that part of it.
Adds return statement and ensures a procedure always has exactly one return statement (which may not always be reachable).
To simplify this we also make the entryBlock and returnBlock of a procedure always defined. The returnBlock must contain a return, and the entryBlock is assumed to have no blocks that jump to it.
internalBlocks
containing the mutable block listProcedure.blocks
returns entryBlock ++ internalBlocks ++ returnBlock.Procedure.hasImplementation
method to define whether the procedure is a stub.addBlock
andremoveBlock
methods on procedure ensure that the only return statement in the procedure is the one in the return block by: