/// <summary> /// Having identified the return variable -- if any -- rewrite all /// return statements to return that variable. /// </summary> /// <param name="ssa"></param> public void RewriteReturns(SsaState ssa) { // For each basic block reaching the exit block, get all reaching // definitions and then either replace the return expression or // inject out variable assignments as Stores. var reachingBlocks = ssa.PredecessorPhiIdentifiers(ssa.Procedure.ExitBlock); var sig = ssa.Procedure.Signature; foreach (var reachingBlock in reachingBlocks) { var block = reachingBlock.Key; var idRet = sig.ReturnValue; if (idRet != null && !(idRet.DataType is VoidType)) { var idStg = reachingBlock.Value .Where(cb => cb.Storage.Covers(idRet.Storage)) .FirstOrDefault(); SetReturnExpression(ssa, block, idRet, idStg); } int insertPos = block.Statements.FindIndex(s => s.Instruction is ReturnInstruction); Debug.Assert(insertPos >= 0); foreach (var p in sig.Parameters.Where(p => p.Storage is OutArgumentStorage)) { var outStg = (OutArgumentStorage)p.Storage; var idStg = reachingBlock.Value .Where(cb => cb.Storage == outStg.OriginalIdentifier.Storage) .FirstOrDefault(); InsertOutArgumentAssignment( ssa, p, idStg?.Expression ?? Constant.Invalid, block, insertPos); ++insertPos; } } }