Je zou nu iets kunnen maken als :
if (add(0x7FFFFFFF,0x20,a)) {
/* geen overflow */
return a;
} else {
/* overflow converteer in real */
return (double)(#7FFFFFFF) + (double)(#20) ;
}
Het probleem zit nu in de funktie add() .
Dit kost veel tyd als je bedenkt dat iedere optelling hierdoor heen moet .
Natuurlijk heb ik dit gedaan en gekonstateerd dat het 30% meer tijd koste .
Een veel elementairdere weg is dit probleem in machine taal optelossen .
Je zou nu iets kunnen maken als :
Niet schelden , dit is een zelf bedachte machine ala PDP9 (one adress machine) .add(arg1,arg2,result): load arg1 -> acc=arg1 add arg2 -> acc=acc+arg2 store result -> result=acc load 0 -> acc=0 jo 1 -> spring naar label 1 indien overflow_bit is gezet cmpl -> acc=-acc 1: nop
Een dergelijk iets kun je in C doen met behulp van 'Extended Asm' . Feitelijk assembler instruktie die je schrijft in een C programma , maar door C worden doorgeven aan de assembler (GAS) .
Deze plaatst de gevraagde machine code inline je C code . Of anders gezegd de gevraagde assembler code wordt in de assembler code gezet die door de C vertaler wordt gemaakt .
Oh ja de vraag wat kost dit aan tyd ? Ik heb gezien dat dit iets tussen de 3% en 5% meer aan tyd kost .
#include <stdio.h>
int sub(long ebx, long eax, long* result ){
long flags,res;
/* ebx = ebx - eax */
__asm__ __volatile__ ("subl %1,%0;movl $0,%1;jo 0f; not %1;0:"
: "=b"((long)*result),"=a"((long)flags)
: "a"((long)eax),
"b"((long)ebx)
);
return flags;
}
int add(long ebx, long eax, long* result ){
long flags,res;
/* ebx = ebx + eax */
__asm__ __volatile__ ("addl %1,%0;movl $0,%1;jo 0f; not %1;0:"
: "=b"((long)*result),"=a"((long)flags)
: "a"((long)eax),
"b"((long)ebx)
);
return flags;
}
int mul(long ebx, long eax, long* result ){
long flags,res;
/* ebx = ebx * eax */
__asm__ __volatile__ ("imull %1,%0;movl $0,%1;jo 0f; not %1;0:"
: "=b"((long)*result),"=a"((long)flags)
: "a"((long)eax),
"b"((long)ebx)
);
return flags;
}
int incr(long ebx, long* result ){
long flags,res;
/* ebx = +1 */
__asm__ __volatile__ ("incl %0;movl $0,%1;jo 0f; not %1;0:"
: "=r"((long)*result),"=r"((long)flags)
: "r"((long)ebx)
);
return flags;
}
int decr(long ebx, long* result ){
long flags;
/* ebx = -1 */
__asm__ __volatile__ ("decl %0;movl $0,%1;jo 0f; not %1;0:"
: "=r"((long)*result),"=r"((long)flags)
: "r"((long)ebx)
);
return flags;
}
int main(void) {
long ebx=4,eax=0x80000003; /* invoer data */
long flags,result;
printf("nTest function's's with underflow/overflow full range n");
flags = incr(ebx,&result);/* result = ebx +1 */
printf("incr %x = %x + 1 ; flags=%x ", result,ebx,flags);
if (flags) printf("Correctn"); else printf("Overflow !!n");
flags = decr(ebx,&result);/* result = ebx -1 */
printf("decr %x = %x - 1 ; flags=%x ", result,ebx,flags);
if (flags) printf("Correctn"); else printf("Overflow !!n");
flags = mul(ebx,eax,&result);/* result = ebx * eax */
printf("mul %x = %x * %x ; flags=%x ", result,ebx,eax,flags);
if (flags) printf("Correctn"); else printf("Overflow !!n");
flags = add(ebx,eax,&result);/* result = ebx + eax */
printf("add %x = %x + %x ; flags=%x ", result,ebx,eax,flags);
if (flags) printf("Correctn"); else printf("Overflow !!n");
flags = sub(ebx,eax,&result);/* result = ebx - eax */
printf("sub %x = %x - %x ; flags=%x ", result,ebx,eax,flags);
if (flags) printf("Correctn"); else printf("Overflow !!n");
return 0;
}
Hier de manier met inline code en een afwijkende ondergrens .
/* define's with a other underflow number (used by PEU) */
#include <stdio.h>
#define decrement(longinteger,longresult) ({ long flags; __asm__ __volatile__ ("movl $0,%1;cmpl $0xfd000000,%0;jle 0f;decl %0;jo 0f; not %1;0:" : "=r"((long)*longresult),"=r"((long)flags) : "r"((long)longinteger) ); flags;})
#define increment(longinteger,longresult) ({ long flags; __asm__ __volatile__ ("incl %0;movl $0,%1;jo 0f;not %1;0:" : "=r"((long)*longresult),"=r"((long)flags) : "r"((long)longinteger) ); flags;})
#define multiply(ebx,eax,result) ({ long flags; /* ebx = ebx * eax */ __asm__ __volatile__ ("imull %1,%0;movl $0,%1;jo 0f;cmpl $0xfd000000,%0;jle 0f; not %1;0:" : "=b"((long)*result),"=a"((long)flags) : "a"((long)eax),"b"((long)ebx) ); flags;})
#define adding(ebx,eax,result) ({ long flags; /* result = ebx + eax */ __asm__ __volatile__ ("addl %1,%0;movl $0,%1;jo 0f;cmpl $0xfd000000,%0;jle 0f; not %1;0:" : "=b"((long)*result),"=a"((long)flags) : "a"((long)eax),"b"((long)ebx) ); flags;})
#define subtract(ebx,eax,result) ({ long flags; /* result = ebx - eax */ __asm__ __volatile__ ("subl %1,%0;movl $0,%1;jo 0f;cmpl $0xfd000000,%0;jle 0f;not %1;0:" : "=b"((long)*result),"=a"((long)flags) : "a"((long)eax),"b"((long)ebx) ); flags;})
int main(void) {
long ebx=4,eax=0x80000003; /* invoer data */
long flags,result;
printf("nTest define's with other underflow value (FD000000) n");
if (increment(ebx,&result)){/* result = ebx +1 */
printf("Increment Oke %x = %x + 1 n", result,ebx);
} else printf("Increment Overflow !!n");
if (decrement(ebx,&result)){/* result = ebx -1 */
printf("Decrement Oke %x = %x - 1 n", result,ebx);
} else printf("Decrement Overflow !!n");
if (multiply(ebx,eax,&result)){/* result = ebx * eax */
printf("Multiply Oke %x = %x * %x n", result,ebx,eax);
} else printf("Multiply Overflow !!n");
if (adding(ebx,eax,&result)){/* result = ebx + eax */
printf("Adding Oke %x = %x + %x n", result,ebx,eax);
} else printf("Adding Overflow !!n");
if (subtract(ebx,eax,&result)){/* result = ebx - eax */
printf("Subtract Oke %x = %x - %x n", result,ebx,eax);
} else printf("Subtract Overflow !!n");
return 0;
}
Bedenk dat de asm(GAS) code de notatie van AT&T gebruikt d.w.z <opr> <source> -> <dist> .
Hopelijk helpt je dit wat . Kommentaar en toevoegingen kun je me altijd eMailen .