#include "tests/malloc.h"
#include <stdio.h>
#include <assert.h>

typedef  unsigned long long int  ULong;
typedef  unsigned long int       UWord;

__attribute__((noinline))
static int my_ffsll ( ULong x )
{
   int i;
   for (i = 0; i < 64; i++) {
      if ((x & 1ULL) == 1ULL)
         break;
      x >>= 1;
   }
   return i+1;
}

/* Find length of string, assuming it is aligned and shorter than 8
   characters.  Little-endian only. */
__attribute__((noinline))
static int aligned_strlen(char *s)
{
    /* This is for 64-bit platforms */
    assert(sizeof(ULong) == 8);
    /* ..and only works for aligned input */
    assert(((unsigned long)s & 0x7) == 0);

    /* read 8 bytes */
    ULong val = *(ULong*)s;
    /* Subtract one from each byte */
    ULong val2 = val - 0x0101010101010101ULL;
    /* Find lowest byte whose high bit changed */
    val2 ^= val;
    val2 &= 0x8080808080808080ULL;

    return (my_ffsll(val2) / 8) - 1;
}

__attribute__((noinline)) void foo ( int x )
{
   __asm__ __volatile__("":::"memory");
}

int
main(int argc, char *argv[])
{
    char *buf = memalign16(5);
    buf[0] = 'a';
    buf[1] = 'b';
    buf[2] = 'c';
    buf[3] = 'd';
    buf[4] = '\0';

    /* --partial-loads-ok=no:  expect addr error (here) */
    /* --partial-loads-ok=yes: expect no error */
    if (aligned_strlen(buf) == 4)
        foo(44);

    /* --partial-loads-ok=no:  expect addr error (here) */
    /* --partial-loads-ok=yes: expect value error (in my_ffsll) */
    buf[4] = 'x';
    if (aligned_strlen(buf) == 0)
        foo(37);

    free(buf);

    /* Also, we need to check that a completely out-of-range,
       word-sized load gives an addressing error regardless of the
       start of --partial-loads-ok=.  *And* that the resulting
       value is completely defined. */
    UWord* words = malloc(3 * sizeof(UWord));
    free(words);

    /* Should ALWAYS give an addr error. */
    UWord  w     = words[1];

    /* Should NEVER give an error (you might expect a value one, but no.) */
    if (w == 0x31415927) {
       fprintf(stderr,
               "Elvis is alive and well and living in Milton Keynes.\n");
    }

    return 0;
}
