/// <summary> /// Collects the storages that are live-out by looking at all known /// call sites and forming the union of all live storages at the call /// site. /// </summary> /// <param name="procCallee">Procedure that was called</param> /// <returns></returns> private Dictionary <Storage, BitRange> CollectLiveOutStorages(Procedure procCallee) { trace.Verbose("== Collecting live out storages of {0}", procCallee.Name); var liveOutStorages = new Dictionary <Storage, BitRange>(); var sig = procCallee.Signature; if (sig.ParametersValid) { // Already have a signature, use that to define the // set of live storages. if (!sig.HasVoidReturn) { liveOutStorages.Add( sig.ReturnValue.Storage, new BitRange(0, sig.ReturnValue.DataType.BitSize)); } } else { var urf = new UsedRegisterFinder(dataFlow, new Procedure[0], eventListener); foreach (Statement stm in program.CallGraph.CallerStatements(procCallee)) { if (!(stm.Instruction is CallInstruction ci)) { continue; } trace.Verbose(" {0}", ci); var ssaCaller = this.procToSsa[stm.Block.Procedure]; foreach (var def in ci.Definitions) { if (!(def.Expression is Identifier id)) { continue; } var sid = ssaCaller.Identifiers[id]; if (sid.Uses.Count > 0) { var br = urf.Classify(ssaCaller, sid, def.Storage, true); trace.Verbose(" {0}: {1}", sid.Identifier.Name, br); if (liveOutStorages.TryGetValue(def.Storage, out BitRange brOld)) { br |= brOld; liveOutStorages[def.Storage] = br; } else if (!br.IsEmpty) { liveOutStorages[def.Storage] = br; } } } } } return(liveOutStorages); }
/// <summary> /// This callback is called from the SccFinder, which passes it a list /// of Procedures that form a SCC. /// </summary> /// <param name="procs"></param> private void UntangleProcedureScc(IList <Procedure> procs) { this.sccProcs = procs.ToHashSet(); flow.CreateFlowsFor(procs); // Convert all procedures in the SCC to SSA form and perform // value propagation. var ssts = procs.Select(ConvertToSsa).ToArray(); this.ssts.AddRange(ssts); DumpWatchedProcedure("After extra stack vars", ssts); // At this point, the computation of ProcedureFlow is possible. var trf = new TrashedRegisterFinder(program, flow, ssts, this.eventListener); trf.Compute(); // New stack based variables may be available now. foreach (var sst in ssts) { var vp = new ValuePropagator(program.SegmentMap, sst.SsaState, program.CallGraph, dynamicLinker, this.eventListener); vp.Transform(); sst.RenameFrameAccesses = true; sst.Transform(); DumpWatchedProcedure("After extra stack vars", sst.SsaState.Procedure); } foreach (var ssa in ssts.Select(sst => sst.SsaState)) { RemoveImplicitRegistersFromHellNodes(ssa); var sac = new SegmentedAccessClassifier(ssa); sac.Classify(); var prj = new ProjectionPropagator(ssa, sac); prj.Transform(); DumpWatchedProcedure("After projection propagation", ssa.Procedure); } var uid = new UsedRegisterFinder(flow, procs, this.eventListener); foreach (var sst in ssts) { var ssa = sst.SsaState; RemovePreservedUseInstructions(ssa); DeadCode.Eliminate(ssa); uid.ComputeLiveIn(ssa, true); var procFlow = flow[ssa.Procedure]; RemoveDeadArgumentsFromCalls(ssa.Procedure, procFlow, ssts); DumpWatchedProcedure("After dead call argument removal", ssa.Procedure); } eventListener.Advance(procs.Count); }