//This is the software interrupt num
//we will use.  See Software Int's for
//picking a num.  Nums are subject to change.

#define I_F_UNARY_MINUS I_USER

asm {

//This changes the sign of the floating
//point val in RAX
F_UNARY_MINUS_INT::
                                PUSH            RAX
                                FLD             U64 [RSP]
                                FCHS
                                FSTP            U64 [RSP]
                                POP             RAX
                                IRET

//This does the same thing, but not as
//an interrupt.
F_UNARY_MINUS_CALL::
                                PUSH            RAX
                                FLD             U64 [RSP]
                                FCHS
                                FSTP            U64 [RSP]
                                POP             RAX
                                RET

//This invokes the interrupt version
//with a C callable function.
_F_UM_INT::
                                PUSH            RBP
                                MOV             RBP, RSP
                                MOV             RAX, SF_ARG1[RBP]
                                INT             I_F_UNARY_MINUS
                                POP             RBP
                                RET1            8

//This invokes the call version
//with a C callable function.
_F_UM_CALL::
                                PUSH            RBP
                                MOV             RBP, RSP
                                MOV             RAX, SF_ARG1[RBP]
                                CALL            F_UNARY_MINUS_CALL
                                POP             RBP
                                RET1            8
}

_extern _F_UM_INT  F64 UnaryMinusInt(F64 d);
_extern _F_UM_CALL F64 UnaryMinusCall(F64 d);

#define SAMPLE_SIZE             1000000
U0 TimeIns()
{
        I64 start, end;
        I64 i, old_irq;

        CPURep;
        old_irq = IntEntrySet(I_F_UNARY_MINUS, F_UNARY_MINUS_INT, IDTET_TRAP);

        //Measure interrupt time
        start = TSCGet;
        for (i = 0; i < SAMPLE_SIZE; i++)
                UnaryMinusInt(pi);
        end = TSCGet;
        "Interrupt Cycles: %10.5f\n", ToF64(end - start) / SAMPLE_SIZE;

        //Measure call time
        start = TSCGet;
        for (i = 0; i < SAMPLE_SIZE; i++)
                UnaryMinusCall(pi);
        end = TSCGet;
        "Call      Cycles: %10.5f\n", ToF64(end - start) / SAMPLE_SIZE;

        IntEntrySet(I_F_UNARY_MINUS, old_irq, IDTET_IRQ);
}

TimeIns;

/*      Program Output
6 Cores 3.395GHz
Interrupt Cycles:  573.98543
Call                    Cycles:          9.74349
*/