static VOID Instrument(INS ins)
{
    UINT32 op = INS_Opcode(ins);

    switch (op)
    {
        case XED_ICLASS_BT:
        case XED_ICLASS_BTC:
        case XED_ICLASS_BTR:
        case XED_ICLASS_BTS:
            // Filter out the BTs we want to look at, we don't expect any in system libraries,
            // but we have seen a bt reg,reg on FC12
            if (INS_IsMemoryRead(ins) && !INS_OperandIsImmediate(ins,1))
                break;
            // Fall through and ignore non mem,reg operations.
        default:
            return;
    }
    
    INS_InsertCall(ins, IPOINT_BEFORE,
                   AFUNPTR(ProcessAddress),
                   IARG_ADDRINT, ADDRINT (formatInstruction(ins)),
                   IARG_MEMORYREAD_SIZE,
                   IARG_MEMORYOP_EA, 0,
                   IARG_REG_VALUE, INS_OperandReg(ins, 1),
                   IARG_END);
}
VOID Instruction(INS ins, VOID *v)
{
    UINT32 where = 0;

    if (INS_Opcode(ins) == XED_ICLASS_FNOP)
    {
        instrumenting = !instrumenting;
    }

    if (!instrumenting)
        return;
    
#if (0)
    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printRegisterDiffs,
                   IARG_THREAD_ID,
                   IARG_CONTEXT,
                   IARG_UINT32, where++,
                   IARG_END);

    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printInstruction, 
                   IARG_THREAD_ID,
                   IARG_ADDRINT, VoidStar2Addrint(formatInstruction(ins)),
                   IARG_END);
#endif

    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printRegisterDiffs,
                   IARG_THREAD_ID,
                   IARG_CONTEXT,
                   IARG_UINT32, where++,
                   IARG_END);

    // Find string ops only.
    if (INS_IsStringop(ins))
    {
        for (UINT32 bit =0; bit < 5; bit++)
        {
            INS_InsertIfCall (ins, IPOINT_AFTER, (AFUNPTR)predicate, IARG_UINT32, bit, IARG_INST_PTR, IARG_END);
            INS_InsertThenCall (ins, IPOINT_AFTER, (AFUNPTR)addCount,IARG_UINT32, bit,  IARG_END);
        }

        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printRegisterDiffs,
                       IARG_THREAD_ID,
                       IARG_CONTEXT,
                       IARG_UINT32, where++,
                       IARG_END);

        INS_InsertCall (ins, IPOINT_BEFORE, (AFUNPTR)countInst, IARG_UINT32, 0, IARG_END);
        INS_InsertCall (ins, IPOINT_AFTER, (AFUNPTR)countInst,  IARG_UINT32, 1, IARG_END);

        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printRegisterDiffs,
                       IARG_THREAD_ID,
                       IARG_CONTEXT,
                       IARG_UINT32, where++,
                       IARG_END);

        INS_InsertCall(
            ins, IPOINT_BEFORE, (AFUNPTR) printSz,
            IARG_MEMORYREAD_SIZE, IARG_INST_PTR,
            IARG_EXECUTING,
            IARG_REG_VALUE, REG_ECX,
            IARG_END);

        INS_InsertCall(
            ins, IPOINT_AFTER, (AFUNPTR) printCntVal,
            IARG_REG_VALUE,REG_ECX,
            IARG_END);

        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printRegisterDiffs,
                       IARG_THREAD_ID,
                       IARG_CONTEXT,
                       IARG_UINT32, where++,
                       IARG_END);

        INS_InsertPredicatedCall(
            ins, IPOINT_BEFORE, (AFUNPTR) printSzPredicated,
            IARG_MEMORYREAD_SIZE, IARG_INST_PTR,
            IARG_EXECUTING,
            IARG_REG_VALUE, REG_ECX,
            IARG_END);

        INS_InsertPredicatedCall(
            ins, IPOINT_AFTER, (AFUNPTR) printCntValPredicated,
            IARG_REG_VALUE,REG_ECX,
            IARG_END);

        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printRegisterDiffs,
                       IARG_THREAD_ID,
                       IARG_CONTEXT,
                       IARG_UINT32, where++,
                       IARG_END);

        if (INS_HasRealRep(ins))
        {
            INS_InsertIfCall(ins, IPOINT_BEFORE, (AFUNPTR)firstTime, IARG_END);
            INS_InsertThenCall(ins, IPOINT_BEFORE, (AFUNPTR)checkFirstRep, IARG_FIRST_REP_ITERATION, IARG_END);

            INS_InsertCall (ins, IPOINT_BEFORE, (AFUNPTR)countReps, IARG_FIRST_REP_ITERATION, IARG_EXECUTING, IARG_END);
        }
    }
}