Hlavní navigace

Názor ke článku Počítání s přetečením v C

  • 9. 10. 2014 19:58

    Jet (neregistrovaný) 77.108.35.---

    Dekuji vsem diskutujicim za podmente pripominky, diky teto diskuzi jsem zjistil, ze gcc-avr podporuje i long long aritmetiku. Jaksi me nenapadlo, ze je to vlastne standard. Dal jsem zjistil, ze tento processor je osmibitovy a ne 32 bitovy - nejak jsem si prilis zvykl na ARM. Pak jsem zjistil, ze gcc-avr preklada naprosto nesmyslnym zpusobem i naprosto jednoduche long long scitani, viz [25]. Ale program fungoval, dokonce lepe nez na PIC, kde jsem to mel v assembleru. Ale nedalo mi to, pustil jsem se do optimalizaci. Nakonec jsem prepsal funkci sum do assembleru a rozepsal cykly ve volajici funkci, aby nerotovala 64 bitove, ale vzala si to byte po byte a rotovala po 8mi bitech. Doba vypoctu sla asi na ctvrtinu.
    Pritom jsem jeste zjistil, ze gcc-avr nedokaze odkazovat na registry long long. Odkazy se delaji %A pro nejnizsi byte, %B pro dalsi a tak dale az po %D, ktery odkazuje na nejvyssi registr longu. Ale jaksi zapomneli podporovat %E az %G. Takze temporary registry jsem musel udelat dva longove misto jednoho long long.

    No a ted ta funkce na scitani, secte dve unsigned long long cisla, a v navratove hodnote vrati carry:

    typedef unsigned long long ull;
    unsigned char sum(ull *r, const ull *a) // *r+=*a, returns carry
    {
    unsigned long int r1;
    unsigned long int r2;

    asm volatile(
    "movw %[z],%[r]" LF
    "movw %[y],%[a]" LF
    "ld %A[tmp1],Z" LF
    "ldd %B[tmp1],Z+1" LF
    "ldd %C[tmp1],Z+2" LF
    "ldd %D[tmp1],Z+3" LF
    "ldd %A[tmp2],Z+4" LF
    "ldd %B[tmp2],Z+5" LF
    "ldd %C[tmp2],Z+6" LF
    "ldd %D[tmp2],Z+7" LF

    "ld __tmp_reg__, Y" LF
    "add %A[tmp1], __tmp_reg__" LF
    "ldd __tmp_reg__, Y+1" LF
    "adc %B[tmp1], __tmp_reg__" LF
    "ldd __tmp_reg__, Y+2" LF
    "adc %C[tmp1], __tmp_reg__" LF
    "ldd __tmp_reg__, Y+3" LF
    "adc %D[tmp1], __tmp_reg__" LF

    "ldd __tmp_reg__, Y+4" LF
    "adc %A[tmp2], __tmp_reg__" LF
    "ldd __tmp_reg__, Y+5" LF
    "adc %B[tmp2], __tmp_reg__" LF
    "ldd __tmp_reg__, Y+6" LF
    "adc %C[tmp2], __tmp_reg__" LF
    "ldd __tmp_reg__, Y+7" LF
    "adc %D[tmp2], __tmp_reg__" LF

    "st Z, %A[tmp1]" LF
    "std Z+1, %B[tmp1]" LF
    "std Z+2, %C[tmp1]" LF
    "std Z+3, %D[tmp1]" LF
    "std Z+4, %A[tmp2]" LF
    "std Z+5, %B[tmp2]" LF
    "std Z+6, %C[tmp2]" LF
    "std Z+7, %D[tmp2]" LF

    "clr %A[tmp1]" LF
    "rol %A[tmp1]" LF // carry -> tmp1

    :[z]"=z"(r), [y]"=y"(a), [tmp1]"=r"(r1), [tmp2]"=r"(r2)
    :[r]"r"(r), [a]"r"(a)
    );
    return r1;
    }