예제 #1
0
        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);
        }
예제 #2
0
파일: SsaMutator.cs 프로젝트: claunia/reko
        /// <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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
 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);
 }
예제 #6
0
            /// <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);
            }
예제 #7
0
        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);
                }
            }
        }
예제 #8
0
        // 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);
        }