private void FuseStorePair(Tuple <UnalignedAccess, UnalignedAccess> pair) { Statement stmL, stmR; if (pair.Item1.isLeft) { stmL = pair.Item1.stm !; stmR = pair.Item2.stm !; } else { stmL = pair.Item2.stm !; stmR = pair.Item1.stm !; } ssa.RemoveUses(stmL); ssa.RemoveUses(stmR); if (pair.Item1.mem is Identifier id) { stmR.Instruction = new Assignment(id, pair.Item1.value !); } else { var memId = ((MemoryAccess)((Store)pair.Item2.stm !.Instruction).Dst).MemoryId; var sidMem = ssa.Identifiers[memId]; sidMem.DefStatement = null; stmR.Instruction = new Store( pair.Item1.mem !, pair.Item1.value !); } stmL.Block.Statements.Remove(stmL); ssa.AddUses(stmR); }
/// <summary> /// Generates a "by-pass" of a register around a Call instruction. /// </summary> /// <remarks> /// If we know that a particular register is incremented/decremented /// by a specific constant amount after calling a procedure, we can remove /// any definitions of that register from the signature of the procedure. /// /// Example: suppose we know that the SP register is incremented by 2 /// after the Call instruction: /// /// call [something] /// uses: SP_42, [other registers] /// defs: SP_94, [other registers] /// /// this function modifies it to look like this: /// /// call [something] /// uses: SP_42, [other registers] /// defs: [other registers] /// SP_94 = SP_42 + 2 /// //$TODO: this really belongs in a CallRewriter type class, /// but because the `master` and the `analysis-development` branches /// are out of sync, we put it in this class instead. /// </remarks> /// <param name="stm">The Statement containing the CallInstruction.</param> /// <param name="call">The CallInstruction.</param> /// <param name="register">The register whose post-call value is incremented.</param> /// <param name="delta">The amount by which to increment the register.</param> public void AdjustRegisterAfterCall( Statement stm, CallInstruction call, RegisterStorage register, int delta) { // Locate the post-call definition of the register, if any var defRegBinding = call.Definitions.Where( u => u.Storage == register) .FirstOrDefault(); if (defRegBinding == null) { return; } var defRegId = defRegBinding.Expression as Identifier; if (defRegId == null) { return; } var usedRegExp = call.Uses .Where(u => u.Storage == register) .Select(u => u.Expression) .FirstOrDefault(); if (usedRegExp == null) { return; } var src = m.AddSubSignedInt(usedRegExp, delta); // Generate a statement that adjusts the register according to // the specified delta. var ass = new Assignment(defRegId, src); var defSid = ssa.Identifiers[defRegId]; var adjustRegStm = InsertStatementAfter(ass, stm); defSid.DefExpression = src; defSid.DefStatement = adjustRegStm; call.Definitions.Remove(defRegBinding); ssa.AddUses(adjustRegStm); }
private void InsertOutArgumentAssignment( SsaState ssa, Identifier parameter, Expression e, Block block, int insertPos) { var iAddr = block.Statements[insertPos].LinearAddress; var stm = block.Statements.Insert( insertPos, iAddr, new Store(parameter, e)); ssa.AddUses(stm); }
/// <summary> /// Generates a "by-pass" of a register around a Call instruction. /// </summary> /// <remarks> /// If we know that a particular register is incremented/decremented /// by a specific constant amount after calling a procedure, we can remove /// any definitions of that register from the signature of the procedure. /// /// Example: suppose we know that the SP register is incremented by 2 /// after the Call instruction: /// /// call [something] /// uses: SP_42, [other registers] /// defs: SP_94, [other registers] /// /// this function modifies it to look like this: /// /// call [something] /// uses: SP_42, [other registers] /// defs: [other registers] /// SP_94 = SP_42 + 2 /// //$TODO: this really belongs in a CallRewriter type class, /// but because the `master` and the `analysis-development` branches /// are out of sync, we put it in this class instead. /// </remarks> /// <param name="stm">The Statement containing the CallInstruction.</param> /// <param name="call">The CallInstruction.</param> /// <param name="register">The register whose post-call value is incremented.</param> /// <param name="delta">The amount by which to increment the register.</param> public void AdjustRegisterAfterCall( Statement stm, CallInstruction call, RegisterStorage register, int delta) { // Locate the post-call definition of the register, if any var defRegBinding = call.Definitions .Where(d => d.Identifier is Identifier idDef && idDef.Storage == register) .FirstOrDefault(); if (defRegBinding == null) { return; } var defRegId = defRegBinding.Identifier as Identifier; if (defRegId == null) { return; } var usedRegExp = call.Uses .Select(u => u.Expression) .OfType <Identifier>() .Where(u => u.Storage == register) .FirstOrDefault(); if (usedRegExp == null) { return; } // Generate an instruction that adjusts the register according to // the specified delta. var src = m.AddConstantWord(usedRegExp, register.DataType, delta); var ass = new Assignment(defRegId, src); var defSid = ssa.Identifiers[defRegId]; // Insert the instruction after the call statement. var adjustRegStm = InsertStatementAfter(ass, stm); // Remove the bypassed register definition from // the call instructions. call.Definitions.Remove(defRegBinding); defSid.DefExpression = src; defSid.DefStatement = adjustRegStm; ssa.AddUses(adjustRegStm); }
private void InsertStackDefinition( Identifier stack, int frameOffset, Statement stmAfter) { var fp = ssa.Procedure.Frame.FramePointer; var pos = stmAfter.Block.Statements.IndexOf(stmAfter); var src = m.AddSubSignedInt(fp, frameOffset); var newStm = stmAfter.Block.Statements.Insert( pos + 1, stmAfter.LinearAddress, new Assignment(stack, src)); ssa.Identifiers[stack].DefStatement = newStm; ssa.AddUses(newStm); }
/// <summary> /// Given a sequence of SSA identifiers in <paramref name="sids"/>, generate /// add a new SSA identifier whose definition is sid_new = SEQ(sids...) and /// place it in the basic block <paramref name="pred"/>. /// </summary> /// <remarks> /// If the SSA identifiers all all slices of the same identifier, short-circuit /// the work by using the sliced identifier directly. /// </remarks> private SsaIdentifier MakeFusedIdentifierInPredecessorBlock(SsaIdentifier[] sids, PhiAssignment[] phis, Identifier idWide, Statement stmPhi, int iBlock, Block pred) { SsaIdentifier sidPred; var sidPreds = phis.Select(p => ssa.Identifiers[(Identifier)p.Src.Arguments[iBlock].Value].DefStatement.Instruction as Assignment).ToArray(); var slices = sidPreds.Select(AsSlice).ToArray(); var aliases = sidPreds.Select(s => s as AliasAssignment).ToArray(); if (slices.All(s => s != null) && AllSame(slices, (a, b) => this.cmp.Equals(a.Expression, b.Expression)) && AllAdjacent(slices)) { if (slices[0].Expression is Identifier id) { // All sids were slices of the same identifier `id`, // so just use that instead. sidPred = ssa.Identifiers[id]; sidPred.Uses.Add(stmPhi); return(sidPred); } } var stmPred = AddStatementToEndOfBlock(pred, sids[0].DefStatement.LinearAddress, null); sidPred = ssa.Identifiers.Add(idWide, stmPred, null, false); var phiArgs = phis.Select(p => p.Src.Arguments[iBlock].Value).ToArray(); stmPred.Instruction = new AliasAssignment( sidPred.Identifier, new MkSequence( sidPred.Identifier.DataType, phiArgs)); this.NewStatements.Add(stmPred); ssa.AddUses(stmPred); sidPred.Uses.Add(stmPhi); return(sidPred); }
private void SetReturnExpression( SsaState ssa, Block block, Identifier idRet, CallBinding idStg) { var e = idStg?.Expression ?? Constant.Invalid; for (int i = block.Statements.Count - 1; i >= 0; --i) { var stm = block.Statements[i]; if (stm.Instruction is ReturnInstruction ret) { if (idRet.DataType.BitSize < e.DataType.BitSize) { int offset = idStg !.Storage.OffsetOf(idRet.Storage); e = new Slice(idRet.DataType, e, offset); } ret.Expression = e; ssa.AddUses(stm); } } }
// On MIPS-LE the sequence // lwl rx,K+3(ry) // lwr rx,K(ry) // is an unaligned read. On MIPS-BE it instead is: // lwl rx,K(ry) // lwr rx,K+3(ry) public void FuseUnalignedLoads(Assignment assR) { var appR = MatchIntrinsicApplication(assR.Src, unalignedLoadsLe); if (appR == null) { return; } var regR = assR.Dst; var stmR = ssa.Identifiers[regR].DefStatement; var memR = appR.Item2.Arguments[1]; var offR = GetOffsetOf(memR); var appL = appR.Item2.Arguments[0] as Application; Statement stmL = null; Assignment assL = null; if (appL == null) { var regL = (Identifier)appR.Item2.Arguments[0]; stmL = ssa.Identifiers[regL].DefStatement; if (stmL == null) { return; } assL = stmL.Instruction as Assignment; if (assL == null) { return; } appL = assL.Src as Application; } var pairL = MatchIntrinsicApplication(appL, unalignedLoadsBe); if (pairL == null) { return; } var applL = pairL.Item2; var memL = appL.Arguments[1]; var offL = GetOffsetOf(memL); Expression mem; if (offR + 3 == offL) { // Little endian use mem = memR; } else if (offL + 3 == offR) { // Big endian use mem = memL; } else { return; } ssa.RemoveUses(stmL); ssa.RemoveUses(stmR); if (assL != null) { assL.Src = appL.Arguments[0]; ssa.AddUses(stmL); } assR.Src = mem; if (stmL != null) { stmL.Block.Statements.Remove(stmL); } ssa.AddUses(stmR); }