Ejemplo n.º 1
0
static unsigned GetRegInfo2 (CodeSeg* S,
                             CodeEntry* E,
                             int Index,
                             Collection* Visited,
                             unsigned Used,
                             unsigned Unused,
                             unsigned Wanted)
/* Recursively called subfunction for GetRegInfo. */
{
    /* Follow the instruction flow recording register usage. */
    while (1) {

        unsigned R;

        /* Check if we have already visited the current code entry. If so,
        ** bail out.
        */
        if (CE_HasMark (E)) {
            break;
        }

        /* Mark this entry as already visited */
        CE_SetMark (E);
        CollAppend (Visited, E);

        /* Evaluate the used registers */
        R = E->Use;
        if (E->OPC == OP65_RTS ||
            ((E->Info & OF_UBRA) != 0 && E->JumpTo == 0)) {
            /* This instruction will leave the function */
            R |= S->ExitRegs;
        }
        if (R != REG_NONE) {
            /* We are not interested in the use of any register that has been
            ** used before.
            */
            R &= ~Unused;
            /* Remember the remaining registers */
            Used |= R;
        }

        /* Evaluate the changed registers */
        if ((R = E->Chg) != REG_NONE) {
            /* We are not interested in the use of any register that has been
            ** used before.
            */
            R &= ~Used;
            /* Remember the remaining registers */
            Unused |= R;
        }

        /* If we know about all registers now, bail out */
        if (((Used | Unused) & Wanted) == Wanted) {
            break;
        }

        /* If the instruction is an RTS or RTI, we're done */
        if ((E->Info & OF_RET) != 0) {
            break;
        }

        /* If we have an unconditional branch, follow this branch if possible,
        ** otherwise we're done.
        */
        if ((E->Info & OF_UBRA) != 0) {

            /* Does this jump have a valid target? */
            if (E->JumpTo) {

                /* Unconditional jump */
                E     = E->JumpTo->Owner;
                Index = -1;             /* Invalidate */

            } else {
                /* Jump outside means we're done */
                break;
            }

        /* In case of conditional branches, follow the branch if possible and
        ** follow the normal flow (branch not taken) afterwards. If we cannot
        ** follow the branch, we're done.
        */
        } else if ((E->Info & OF_CBRA) != 0) {

            /* Recursively determine register usage at the branch target */
            unsigned U1;
            unsigned U2;

            if (E->JumpTo) {

                /* Jump to internal label */
                U1 = GetRegInfo2 (S, E->JumpTo->Owner, -1, Visited, Used, Unused, Wanted);

            } else {

                /* Jump to external label. This will effectively exit the
                ** function, so we use the exitregs information here.
                */
                U1 = S->ExitRegs;

            }

            /* Get the next entry */
            if (Index < 0) {
                Index = CS_GetEntryIndex (S, E);
            }
            if ((E = CS_GetEntry (S, ++Index)) == 0) {
                Internal ("GetRegInfo2: No next entry!");
            }

            /* Follow flow if branch not taken */
            U2 = GetRegInfo2 (S, E, Index, Visited, Used, Unused, Wanted);

            /* Registers are used if they're use in any of the branches */
            return U1 | U2;

        } else {

            /* Just go to the next instruction */
            if (Index < 0) {
                Index = CS_GetEntryIndex (S, E);
            }
            E = CS_GetEntry (S, ++Index);
            if (E == 0) {
                /* No next entry */
                Internal ("GetRegInfo2: No next entry!");
            }

        }

    }

    /* Return to the caller the complement of all unused registers */
    return Used;
}
Ejemplo n.º 2
0
int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
/* Check if the given code segment range is a basic block. That is, check if
 * First is the only entrance and Last is the only exit. This means that no
 * jump/branch inside the block may jump to an insn below First or after(!)
 * Last, and that no insn may jump into this block from the outside.
 */
{
    unsigned I;

    /* Don't accept invalid ranges */
    CHECK (First <= Last);

    /* First pass: Walk over the range and remove all marks from the entries */
    CS_ResetMarks (S, First, Last);

    /* Second pass: Walk over the range checking all labels. Note: There may be
     * label on the first insn which is ok.
     */
    I = First + 1;
    while (I <= Last) {

        /* Get the next entry */
        CodeEntry* E = CS_GetEntry (S, I);

        /* Check if this entry has one or more labels, if so, check which
         * entries jump to this label.
         */
        unsigned LabelCount = CE_GetLabelCount (E);
        unsigned LabelIndex;
        for (LabelIndex = 0; LabelIndex < LabelCount; ++LabelIndex) {

            /* Get this label */
            CodeLabel* L = CE_GetLabel (E, LabelIndex);

            /* Walk over all entries that jump to this label. Check for each
             * of the entries if it is out of the range.
             */
            unsigned RefCount = CL_GetRefCount (L);
            unsigned RefIndex;
            for (RefIndex = 0; RefIndex < RefCount; ++RefIndex) {

                /* Get the code entry that jumps here */
                CodeEntry* Ref = CL_GetRef (L, RefIndex);

                /* Walk over out complete range and check if we find the
                 * refering entry. This is cheaper than using CS_GetEntryIndex,
                 * because CS_GetEntryIndex will search the complete code
                 * segment and not just our range.
                 */
                unsigned J;
                for (J = First; J <= Last; ++J) {
                    if (Ref == CS_GetEntry (S, J)) {
                        break;
                    }
                }
                if (J > Last) {
                    /* We did not find the entry. This means that the jump to
                     * out code segment entry E came from outside the range,
                     * which in turn means that the given range is not a basic
                     * block.
                     */
                    CS_ResetMarks (S, First, Last);
                    return 0;
                }

                /* If we come here, we found the entry. Mark it, so we know
                 * that the branch to the label is in range.
                 */
                CE_SetMark (Ref);
            }
        }

        /* Next entry */
        ++I;
    }

    /* Third pass: Walk again over the range and check all branches. If we
     * find a branch that is not marked, its target is not inside the range
     * (since we checked all the labels in the range before).
     */
    I = First;
    while (I <= Last) {

        /* Get the next entry */
        CodeEntry* E = CS_GetEntry (S, I);

        /* Check if this is a branch and if so, if it has a mark */
        if (E->Info & (OF_UBRA | OF_CBRA)) {
            if (!CE_HasMark (E)) {
                /* No mark means not a basic block. Before bailing out, be sure
                 * to remove the marks from the remaining entries.
                 */
                CS_ResetMarks (S, I+1, Last);
                return 0;
            }

            /* Remove the mark */
            CE_ResetMark (E);
        }

        /* Next entry */
        ++I;
    }

    /* Done - this is a basic block */
    return 1;
}