Branch: Tag:

2017-10-08

2017-10-08 11:53:17 by Arne Goedeke <el@laramies.com>

utf8_to_string: use local variables

Due to C aliasing rules, the compiler has to reload the string pointer
and length in every iteration. Use local variables to make the generated
code better.

This new version of utf8_to_string is significantly faster than the
previous 8.1 baseline:

utf8/code.pike#decode_7bit | 1.8 G 2.5 % | 24.2 G 3.5 % |
utf8/code.pike#decode_8bit | 350.0 M 1.8 % | 552.2 M 1.1 % |
utf8/code.pike#decode_arabic | 325.7 M 0.8 % | 438.0 M 1.0 % |
utf8/code.pike#decode_bulgarian | 321.8 M 0.9 % | 378.8 M 2.2 % |
utf8/code.pike#decode_estonian | 375.6 M 1.1 % | 503.0 M 0.9 % |
utf8/code.pike#decode_hebrew | 325.8 M 0.8 % | 438.8 M 0.9 % |
utf8/code.pike#decode_japanese | 391.3 M 1.9 % | 517.5 M 1.8 % |
utf8/code.pike#decode_polish | 371.9 M 0.9 % | 583.2 M 3.8 % |
utf8/code.pike#decode_thai | 377.8 M 0.8 % | 510.6 M 1.0 % |
utf8/code.pike#decode_yiddish | 326.2 M 1.1 % | 443.3 M 0.7 % |

This are the results on my i7.

2194:    struct pike_string *out;    ptrdiff_t len = 0;    int shift = 0; -  ptrdiff_t i,j=0; +     INT_TYPE extended = 0;    INT32 min, max;   
2221:    switch (shift) {    case 0: {    p_wchar0 *out_str = STR0 (out); -  for(i=0; i < in->len;) { -  unsigned int c = STR0(in)[i++]; +  const p_wchar0 *in_str = STR0(in); +  ptrdiff_t len = out->len; +  +  for(ptrdiff_t j=0; j < len; j++) { +  unsigned int c = *(in_str++);    /* NOTE: No tests here since we've already tested the string above. */    if (c & 0x80) {    /* 11bit */ -  unsigned int c2 = STR0(in)[i++] & 0x3f; +  unsigned int c2 = *(in_str++) & 0x3f;    c &= 0x1f;    c = (c << 6) | c2;    } -  out_str[j++] = c; +  out_str[j] = c;    }    break;    }       case 1: {    p_wchar1 *out_str = STR1 (out); -  for(i=0; i < in->len;) { -  unsigned int c = STR0(in)[i++]; +  const p_wchar0 *in_str = STR0(in); +  ptrdiff_t len = out->len; +  +  for(ptrdiff_t j=0; j < len; j++) { +  unsigned int c = *(in_str++);    /* NOTE: No tests here since we've already tested the string above. */    if (c & 0x80) {    if ((c & 0xe0) == 0xc0) {    /* 11bit */ -  unsigned int c2 = STR0(in)[i++] & 0x3f; +  unsigned int c2 = *(in_str++) & 0x3f;    c &= 0x1f;    c = (c << 6) | c2;    } else {    /* 16bit */ -  unsigned int c2 = STR0(in)[i++] & 0x3f; -  unsigned int c3 = STR0(in)[i++] & 0x3f; +  unsigned int c2 = *(in_str++) & 0x3f; +  unsigned int c3 = *(in_str++) & 0x3f;    c &= 0x0f;    c = (c << 12) | (c2 << 6) | c3;    }    } -  out_str[j++] = c; +  out_str[j] = c;    }    break;    }       case 2: {    p_wchar2 *out_str = STR2 (out); -  for(i=0; i < in->len;) { -  unsigned int c = STR0(in)[i++]; +  const p_wchar0 *in_str = STR0(in); +  ptrdiff_t len = out->len; +  +  for(ptrdiff_t j=0; j < len; j++) { +  unsigned int c = *(in_str++);    /* NOTE: No tests here since we've already tested the string above. */    if (c & 0x80) {    int cont = 0;
2292:    c = 0;    }    while(cont--) { -  unsigned int c2 = STR0(in)[i++] & 0x3f; +  unsigned int c2 = *(in_str++) & 0x3f;    c = (c << 6) | c2;    }    if ((extended & 2) && (c & 0xfc00) == 0xdc00) {
2301:    c |= ((out_str[--j] & 0x3ff)<<10) + 0x10000;    }    } -  out_str[j++] = c; +  out_str[j] = c;    }    break;    }