public SsaIdentifier ReadVariableRecursive(SsaBlockState bs) { SsaIdentifier val; if (bs.Block.Pred.Any(p => !blockstates[p].Visited)) { // Incomplete CFG val = NewPhi(id, bs.Block); outer.incompletePhis.Add(val); } else if (bs.Block.Pred.Count == 0) { // Undef'ined or unreachable parameter; assume it's a def. val = NewDefInstruction(id, bs.Block); } else if (bs.Block.Pred.Count == 1) { // Search for the variable in the single predecessor. val = ReadVariable(blockstates[bs.Block.Pred[0]]); } else { // Break potential cycles with operandless phi val = NewPhi(id, bs.Block); WriteVariable(bs, val); val = AddPhiOperands(val); } if (val != null) { WriteVariable(bs, val); } return(val); }
/// <summary> /// Reaches "backwards" to locate the SSA identifier that defines /// the identifier <paramref name="id"/>, starting in block <paramref name="b"/>. /// </summary> /// If no definition of <paramref name="id"/> is found, a new /// DefStatement is created in the entry block of the procedure. /// </summary> /// <param name="bs"></param> /// <returns>The SSA name of the identifier that was read.</returns> public virtual SsaIdentifier ReadVariable(SsaBlockState bs) { trace.Verbose("ReadVariable {0} in block {1}", this.id, bs.Block.Name); if (bs.Terminates) { // Reko has determined that this block diverges. We fall back to // getting a variable from the entry block, which is guaranteed to // dominate every other block in the procedure. bs = outer.blockstates[bs.Block.Procedure.EntryBlock]; } var sid = ReadBlockLocalVariable(bs); if (sid != null) { return(sid); } // Keep probin'. // The commented-out code below is for assistance when troubleshooting // stack overflows in the code. These are always caused by the // CFG of the Procedure being malformed due to errors in the Scanning // phase. Once #726 is addressed, there should be no need for this // code. //if (++this.depth > 1000) // throw new StackOverflowException(""); sid = ReadVariableRecursive(bs); //--this.depth; return(sid !); }
/// <summary> /// Reaches "backwards" to locate the SSA identifier that defines /// the identifier <paramref name="id"/>, starting in block <paramref name="b"/>. /// </summary> /// If no definition of <paramref name="id"/> is found, a new /// DefStatement is created in the entry block of the procedure. /// </summary> /// <param name="bs"></param> /// <returns>The SSA name of the identifier that was read.</returns> public virtual SsaIdentifier ReadVariable(SsaBlockState bs) { if (bs.Terminates) { // Reko has determined that this block diverges. We fall back to // getting a variable from the entry block, which is guaranteed to // dominate every other block in the procedure. bs = outer.blockstates[bs.Block.Procedure.EntryBlock]; } var sid = ReadBlockLocalVariable(bs); if (sid != null) { return(sid); } // Keep probin'. return(ReadVariableRecursive(bs)); }
private void ReplaceStackDefs( SsaBlockState bs, SsaIdentifier sidOld, SsaIdentifier sidNew) { if (!(sidOld.Identifier.Storage is StackStorage stack)) { return; } var offsetInterval = Interval.Create( stack.StackOffset, stack.StackOffset + sidOld.Identifier.DataType.Size); var ints = bs.currentStackDef .GetIntervalsOverlappingWith(offsetInterval).ToArray(); foreach (var de in ints) { if (de.Value.SsaId == sidOld) { de.Value.SsaId = sidNew; } } }
/// <summary> /// Registers the fact that identifier <paramref name="id"/> is /// modified in the block <paramref name="b" /> and generates a /// fresh SSA identifier. /// </summary> /// <param name="bs">The block in which the identifier was changed</param> /// <param name="sid">The identifier after being SSA transformed.</param> /// <returns>The new SSA identifier</returns> public override Identifier WriteVariable(SsaBlockState bs, SsaIdentifier sid) { DebugEx.Verbose(trace, " WriteBlockLocalVariable: ({0}, {1}, ({2})", bs.Block.Name, id, this.liveBits); if (!bs.currentDef.TryGetValue(id.Storage.Domain, out var aliasState)) { aliasState = new AliasState(); bs.currentDef.Add(id.Storage.Domain, aliasState); } var stgDef = id.Storage; var defRange = stgDef.GetBitRange(); for (int i = 0; i < aliasState.Definitions.Count; ++i) { var(sidPrev, prevRange, offset) = aliasState.Definitions[i]; var stgPrev = sidPrev.Identifier.Storage; if (defRange.Covers(prevRange)) { DebugEx.Verbose(trace, " overwriting: {0}", sidPrev.Identifier); aliasState.Definitions.RemoveAt(i); --i; } } aliasState.Definitions.Add((sid, defRange, this.Offset)); DebugEx.Verbose(trace, " writing: {0}", sid.Identifier); var newDict = aliasState.ExactAliases .Where(kv => !kv.Key.OverlapsWith(id.Storage)) .ToDictionary(kv => kv.Key, kv => kv.Value); if (id.Storage == sid.Identifier.Storage) { newDict[id.Storage] = sid; } aliasState.ExactAliases = newDict; return(sid.Identifier); }
/// <summary> /// If the `id` has an SsaIdentifier available (not necessarily /// defined) in this block, return that SsaIdentifier. /// </summary> /// <param name="bs">SsaBlockState we look in.</param> /// <returns>An SsaIdentifier if it is available, /// otherwise null. /// </returns> public abstract SsaIdentifier ReadBlockLocalVariable(SsaBlockState bs);
public abstract Identifier WriteVariable(SsaBlockState bs, SsaIdentifier sid);
public override SsaIdentifier ReadBlockLocalVariable(SsaBlockState bs) { DebugEx.Verbose(trace, " ReadBlockLocalVariable: ({0}, {1}, ({2})", bs.Block.Name, id, this.liveBits); if (!bs.currentDef.TryGetValue(id.Storage.Domain, out var alias)) { return(null); } // Identifier id is defined locally in this block. // Has an exact alias already been calculated? if (alias.ExactAliases.TryGetValue(id.Storage, out var sid)) { DebugEx.Verbose(trace, " found alias ({0}, {1})", bs.Block.Name, sid.Identifier.Name); return(sid); } // At least some of the bits of 'id' are defined locally in this // block. Walk across the bits of 'id', collecting all parts // defined into a sequence. int offsetLo = this.liveBits.Lsb; int offsetHi = this.liveBits.Msb; var sids = new List <(SsaIdentifier, BitRange)>(); while (offsetLo < offsetHi) { var useRange = new BitRange(offsetLo, offsetHi); var(sidElem, usedRange, defRange) = FindIntersectingRegister(alias.Definitions, useRange); if (sidElem == null || offsetLo < usedRange.Lsb) { // Found a gap in the register that wasn't defined in // this basic block. Seek backwards var bitrangeR = sidElem == null ? useRange : new BitRange(offsetLo, usedRange.Lsb); var idR = MakeTmpIdentifier(sidElem, bitrangeR); var rx = new RegisterTransformer(idR, stm, this.outer) { liveBits = bitrangeR }; var sidR = rx.ReadVariableRecursive(bs); sids.Add((sidR, bitrangeR)); offsetLo = bitrangeR.Msb; } if (sidElem != null) { sids.Add((sidElem, defRange)); offsetLo = usedRange.Msb; } } if (sids.Count == 1) { var sidSlice = MakeSlice(sids[0].Item1, sids[0].Item2, this.id); alias.ExactAliases[this.id.Storage] = sidSlice; return(sidSlice); } else { sids.Reverse(); // Order sids in big-endian order var elems = new List <Expression>(); foreach (var(sidElem, bitrange) in sids) { var idSlice = MakeTmpIdentifier(sidElem, bitrange); var sidSlice = MakeSlice(sidElem, bitrange, idSlice); alias.ExactAliases[sidSlice.OriginalIdentifier.Storage] = sidSlice; elems.Add(sidSlice.Identifier); } var seq = outer.m.Seq(elems.ToArray()); var assSeq = new AliasAssignment(id, seq); var sidTo = InsertBeforeStatement(bs.Block, this.stm, assSeq); seq.Accept(new InstructionUseAdder(sidTo.DefStatement, ssaIds)); alias.ExactAliases[this.id.Storage] = sidTo; return(sidTo); } }