Je zou nu iets kunnen maken als :
Het probleem zit nu in de funktie add() .if (add(0x7FFFFFFF,0x20,a)) { /* geen overflow */ return a; } else { /* overflow converteer in real */ return (double)(#7FFFFFFF) + (double)(#20) ; }
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("Correct\n"); else printf("Overflow !!\n"); flags = decr(ebx,&result);/* result = ebx -1 */ printf("decr %x = %x - 1 ; flags=%x ", result,ebx,flags); if (flags) printf("Correct\n"); 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("Correct\n"); 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("Correct\n"); 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("Correct\n"); 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 .
Menno S Ter Haseborg