about summary refs log tree commit diff
path: root/sysdeps/tile/tilegx
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2014-02-10 10:54:47 -0500
committerChris Metcalf <cmetcalf@tilera.com>2014-02-10 11:04:39 -0500
commit4372980f5881e7d537a52e3c49588ce116088061 (patch)
tree138fbc88313c8cb0cabee393e0c08afd67dac6f1 /sysdeps/tile/tilegx
parenta1ffb40e32741f992c743e7b16c061fefa3747ac (diff)
downloadglibc-4372980f5881e7d537a52e3c49588ce116088061.tar.gz
glibc-4372980f5881e7d537a52e3c49588ce116088061.tar.xz
glibc-4372980f5881e7d537a52e3c49588ce116088061.zip
Move tilegx, tilepro, and linux-generic from ports to libc.
I've moved the TILE-Gx and TILEPro ports to the main sysdeps hierarchy,
along with the linux-generic ports infrastructure.  Beyond the README
update, the move was just

    git mv ports/sysdeps/tile sysdeps/tile
    git mv ports/sysdeps/unix/sysv/linux/tile \
      sysdeps/unix/sysv/linux/tile
    git mv ports/sysdeps/unix/sysv/linux/generic \
      sysdeps/unix/sysv/linux/generic

I updated the relevant ChangeLogs along the lines of the ARM move
in commit c6bfe5c4d75 and tested the 64-bit tilegx build to confirm that
there were no changes in "objdump -dr" output in the shared objects.
Diffstat (limited to 'sysdeps/tile/tilegx')
-rw-r--r--sysdeps/tile/tilegx/Makefile35
-rw-r--r--sysdeps/tile/tilegx/bits/atomic.h49
-rw-r--r--sysdeps/tile/tilegx/bits/wordsize.h8
-rw-r--r--sysdeps/tile/tilegx/memchr.c73
-rw-r--r--sysdeps/tile/tilegx/memcpy.c272
-rw-r--r--sysdeps/tile/tilegx/memmove.c22
-rw-r--r--sysdeps/tile/tilegx/memset.c151
-rw-r--r--sysdeps/tile/tilegx/memusage.h31
-rw-r--r--sysdeps/tile/tilegx/rawmemchr.c45
-rw-r--r--sysdeps/tile/tilegx/strchr.c67
-rw-r--r--sysdeps/tile/tilegx/strchrnul.c64
-rw-r--r--sysdeps/tile/tilegx/string-endian.h47
-rw-r--r--sysdeps/tile/tilegx/strlen.c39
-rw-r--r--sysdeps/tile/tilegx/strrchr.c68
-rw-r--r--sysdeps/tile/tilegx/tilegx32/Implies3
-rw-r--r--sysdeps/tile/tilegx/tilegx64/Implies3
16 files changed, 977 insertions, 0 deletions
diff --git a/sysdeps/tile/tilegx/Makefile b/sysdeps/tile/tilegx/Makefile
new file mode 100644
index 0000000000..4281dd98fc
--- /dev/null
+++ b/sysdeps/tile/tilegx/Makefile
@@ -0,0 +1,35 @@
+include $(common-objpfx)cflags-mcmodel-large.mk
+
+# Check for gcc to support the command-line switch, and for
+# binutils to support the hwN_plt() assembly operators and relocations.
+$(common-objpfx)cflags-mcmodel-large.mk: $(common-objpfx)config.make
+	mcmodel=no; \
+	(echo 'int main() { return getuid(); }' | \
+	 $(CC) -o /dev/null -xc - -mcmodel=large -fpic) && mcmodel=yes; \
+	echo "cflags-mcmodel-large = $$mcmodel" > $@
+
+ifeq (yes,$(cflags-mcmodel-large))
+
+ifeq ($(subdir),csu)
+# elf-init.c is in libc_nonshared.o (the end of the shared object) but
+# must reach the _init symbol at the very start of the shared object.
+CFLAGS-elf-init.c += -mcmodel=large
+
+# __gmon_start__ is at the very start of the shared object when linked
+# with profiling, but calls to libc.so via the PLT at the very end.
+CFLAGS-gmon-start.c += -mcmodel=large
+endif
+
+else
+
+# Don't try to compile assembly code with hwN_plt() directives if the
+# toolchain doesn't support -mcmodel=large.
+ifeq ($(subdir),csu)
+CPPFLAGS-start.S += -DNO_PLT_PCREL
+CPPFLAGS-crti.S += -DNO_PLT_PCREL
+endif
+ifeq ($(subdir),nptl)
+CPPFLAGS-pt-crti.S += -DNO_PLT_PCREL
+endif
+
+endif
diff --git a/sysdeps/tile/tilegx/bits/atomic.h b/sysdeps/tile/tilegx/bits/atomic.h
new file mode 100644
index 0000000000..ce12db0216
--- /dev/null
+++ b/sysdeps/tile/tilegx/bits/atomic.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H	1
+
+#include <arch/spr_def.h>
+
+/* Pick appropriate 8- or 4-byte instruction. */
+#define __atomic_update(mem, v, op)                                     \
+  ((__typeof (*(mem))) (__typeof (*(mem) - *(mem)))                     \
+   ((sizeof (*(mem)) == 8) ?                                            \
+    __insn_##op ((void *) (mem), (int64_t) (__typeof((v) - (v))) (v)) : \
+    (sizeof (*(mem)) == 4) ?                                            \
+    __insn_##op##4 ((void *) (mem), (int32_t) (__typeof ((v) - (v))) (v)) : \
+    __atomic_error_bad_argument_size()))
+
+#define atomic_compare_and_exchange_val_acq(mem, n, o)                  \
+  ({ __insn_mtspr (SPR_CMPEXCH_VALUE, (int64_t) (__typeof ((o) - (o))) (o)); \
+     __atomic_update (mem, n, cmpexch); })
+#define atomic_exchange_acq(mem, newvalue) \
+  __atomic_update (mem, newvalue, exch)
+#define atomic_exchange_and_add(mem, value) \
+  __atomic_update (mem, value, fetchadd)
+#define atomic_and_val(mem, mask) \
+  __atomic_update (mem, mask, fetchand)
+#define atomic_or_val(mem, mask) \
+  __atomic_update (mem, mask, fetchor)
+#define atomic_decrement_if_positive(mem) \
+  __atomic_update (mem, -1, fetchaddgez)
+
+#include <sysdeps/tile/bits/atomic.h>
+
+#endif /* bits/atomic.h */
diff --git a/sysdeps/tile/tilegx/bits/wordsize.h b/sysdeps/tile/tilegx/bits/wordsize.h
new file mode 100644
index 0000000000..5d4e4b4470
--- /dev/null
+++ b/sysdeps/tile/tilegx/bits/wordsize.h
@@ -0,0 +1,8 @@
+/* Determine the wordsize from the preprocessor defines.  */
+
+#ifdef __LP64__
+# define __WORDSIZE	64
+# define __WORDSIZE_TIME64_COMPAT32	1
+#else
+# define __WORDSIZE	32
+#endif
diff --git a/sysdeps/tile/tilegx/memchr.c b/sysdeps/tile/tilegx/memchr.c
new file mode 100644
index 0000000000..ee17d9a40a
--- /dev/null
+++ b/sysdeps/tile/tilegx/memchr.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+void *
+__memchr (const void *s, int c, size_t n)
+{
+  const uint64_t *last_word_ptr;
+  const uint64_t *p;
+  const char *last_byte_ptr;
+  uintptr_t s_int;
+  uint64_t goal, before_mask, v, bits;
+  char *ret;
+
+  if (__builtin_expect (n == 0, 0))
+    {
+      /* Don't dereference any memory if the array is empty. */
+      return NULL;
+    }
+
+  /* Get an aligned pointer. */
+  s_int = (uintptr_t) s;
+  p = (const uint64_t *) (s_int & -8);
+
+  /* Create eight copies of the byte for which we are looking. */
+  goal = copy_byte(c);
+
+  /* Read the first word, but munge it so that bytes before the array
+     will not match goal.  */
+  before_mask = MASK (s_int);
+  v = (*p | before_mask) ^ (goal & before_mask);
+
+  /* Compute the address of the last byte. */
+  last_byte_ptr = (const char *) s + n - 1;
+
+  /* Compute the address of the word containing the last byte. */
+  last_word_ptr = (const uint64_t *) ((uintptr_t) last_byte_ptr & -8);
+
+  while ((bits = __insn_v1cmpeq (v, goal)) == 0)
+    {
+      if (__builtin_expect (p == last_word_ptr, 0))
+        {
+          /* We already read the last word in the array, so give up.  */
+          return NULL;
+        }
+      v = *++p;
+    }
+
+  /* We found a match, but it might be in a byte past the end
+     of the array.  */
+  ret = ((char *) p) + (CFZ (bits) >> 3);
+  return (ret <= last_byte_ptr) ? ret : NULL;
+}
+weak_alias (__memchr, memchr)
+libc_hidden_builtin_def (memchr)
diff --git a/sysdeps/tile/tilegx/memcpy.c b/sysdeps/tile/tilegx/memcpy.c
new file mode 100644
index 0000000000..5d5df19ef3
--- /dev/null
+++ b/sysdeps/tile/tilegx/memcpy.c
@@ -0,0 +1,272 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <memcopy.h>
+#include <arch/chip.h>
+
+/* How many cache lines ahead should we prefetch? */
+#define PREFETCH_LINES_AHEAD 3
+
+void *
+__memcpy (void *__restrict dstv, const void *__restrict srcv, size_t n)
+{
+  char *__restrict dst1 = (char *) dstv;
+  const char *__restrict src1 = (const char *) srcv;
+  const char *__restrict src1_end;
+  const char *__restrict prefetch;
+  op_t *__restrict dst8; /* 8-byte pointer to destination memory. */
+  op_t final; /* Final bytes to write to trailing word, if any */
+  long i;
+
+  if (n < 16)
+    {
+      for (; n; n--)
+        *dst1++ = *src1++;
+      return dstv;
+    }
+
+  /* Locate the end of source memory we will copy.  Don't prefetch
+     past this.  */
+  src1_end = src1 + n - 1;
+
+  /* Prefetch ahead a few cache lines, but not past the end. */
+  prefetch = src1;
+  for (i = 0; i < PREFETCH_LINES_AHEAD; i++)
+    {
+      __insn_prefetch (prefetch);
+      prefetch += CHIP_L2_LINE_SIZE ();
+      prefetch = (prefetch < src1_end) ? prefetch : src1;
+    }
+
+  /* Copy bytes until dst is word-aligned. */
+  for (; (uintptr_t) dst1 & (sizeof (op_t) - 1); n--)
+    *dst1++ = *src1++;
+
+  /* 8-byte pointer to destination memory. */
+  dst8 = (op_t *) dst1;
+
+  if (__builtin_expect ((uintptr_t) src1 & (sizeof (op_t) - 1), 0))
+    {
+      /* Misaligned copy.  Use glibc's _wordcopy_fwd_dest_aligned, but
+         inline it to avoid prologue/epilogue.  TODO: Consider
+         prefetching and using wh64 as well.  */
+      void * srci;
+      op_t a0, a1, a2, a3;
+      long int dstp = (long int) dst1;
+      long int srcp = (long int) src1;
+      long int len = n / OPSIZ;
+
+      /* Save the initial source pointer so we know the number of
+         bytes to shift for merging two unaligned results.  */
+      srci = (void *) srcp;
+
+      /* Make SRCP aligned by rounding it down to the beginning of the
+         `op_t' it points in the middle of.  */
+      srcp &= -OPSIZ;
+
+      switch (len % 4)
+	{
+	case 2:
+	  a1 = ((op_t *) srcp)[0];
+	  a2 = ((op_t *) srcp)[1];
+	  len += 2;
+	  srcp += 2 * OPSIZ;
+	  goto do1;
+	case 3:
+	  a0 = ((op_t *) srcp)[0];
+	  a1 = ((op_t *) srcp)[1];
+	  len += 1;
+	  srcp += 2 * OPSIZ;
+	  goto do2;
+	case 0:
+	  if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+	    return dstv;
+	  a3 = ((op_t *) srcp)[0];
+	  a0 = ((op_t *) srcp)[1];
+	  len += 0;
+	  srcp += 2 * OPSIZ;
+	  goto do3;
+	case 1:
+	  a2 = ((op_t *) srcp)[0];
+	  a3 = ((op_t *) srcp)[1];
+	  srcp += 2 * OPSIZ;
+	  len -= 1;
+	  if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+	    goto do0;
+	  goto do4;			/* No-op.  */
+	}
+
+      do
+	{
+	do4:
+	  a0 = ((op_t *) srcp)[0];
+	  a2 = __insn_dblalign (a2, a3, srci);
+	  ((op_t *) dstp)[0] = a2;
+	  srcp += OPSIZ;
+	  dstp += OPSIZ;
+	do3:
+	  a1 = ((op_t *) srcp)[0];
+	  a3 = __insn_dblalign (a3, a0, srci);
+	  ((op_t *) dstp)[0] = a3;
+	  srcp += OPSIZ;
+	  dstp += OPSIZ;
+	do2:
+	  a2 = ((op_t *) srcp)[0];
+	  a0 = __insn_dblalign (a0, a1, srci);
+	  ((op_t *) dstp)[0] = a0;
+	  srcp += OPSIZ;
+	  dstp += OPSIZ;
+	do1:
+	  a3 = ((op_t *) srcp)[0];
+	  a1 = __insn_dblalign (a1, a2, srci);
+	  ((op_t *) dstp)[0] = a1;
+	  srcp += OPSIZ;
+	  dstp += OPSIZ;
+	  len -= 4;
+	}
+      while (len != 0);
+
+      /* This is the right position for do0.  Please don't move
+         it into the loop.  */
+    do0:
+      ((op_t *) dstp)[0] = __insn_dblalign (a2, a3, srci);
+
+      n = n % OPSIZ;
+      if (n == 0)
+	return dstv;
+
+      a0 = ((const char *) srcp <= src1_end) ? ((op_t *) srcp)[0] : 0;
+
+      final = __insn_dblalign (a3, a0, srci);
+      dst8 = (op_t *)(dstp + OPSIZ);
+    }
+  else
+    {
+      /* Aligned copy. */
+
+      const op_t *__restrict src8 = (const op_t *) src1;
+
+      /* src8 and dst8 are both word-aligned. */
+      if (n >= CHIP_L2_LINE_SIZE ())
+        {
+          /* Copy until 'dst' is cache-line-aligned. */
+          for (; (uintptr_t) dst8 & (CHIP_L2_LINE_SIZE () - 1);
+               n -= sizeof (op_t))
+            *dst8++ = *src8++;
+
+          for (; n >= CHIP_L2_LINE_SIZE ();)
+	    {
+	      op_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+
+	      /* Prefetch and advance to next line to prefetch, but
+		 don't go past the end.  */
+	      __insn_prefetch (prefetch);
+	      prefetch += CHIP_L2_LINE_SIZE ();
+	      prefetch = (prefetch < src1_end) ? prefetch :
+		(const char *) src8;
+
+	      /* Do all the loads before wh64.  This is necessary if
+		 [src8, src8+7] and [dst8, dst8+7] share the same
+		 cache line and dst8 <= src8, as can be the case when
+		 called from memmove, or with code tested on x86 whose
+		 memcpy always works with forward copies.  */
+	      tmp0 = *src8++;
+	      tmp1 = *src8++;
+	      tmp2 = *src8++;
+	      tmp3 = *src8++;
+	      tmp4 = *src8++;
+	      tmp5 = *src8++;
+	      tmp6 = *src8++;
+	      tmp7 = *src8++;
+
+	      __insn_wh64 (dst8);
+
+	      *dst8++ = tmp0;
+	      *dst8++ = tmp1;
+	      *dst8++ = tmp2;
+	      *dst8++ = tmp3;
+	      *dst8++ = tmp4;
+	      *dst8++ = tmp5;
+	      *dst8++ = tmp6;
+	      *dst8++ = tmp7;
+
+	      n -= 64;
+	    }
+#if CHIP_L2_LINE_SIZE() != 64
+# error "Fix code that assumes particular L2 cache line size."
+#endif
+        }
+
+      for (; n >= sizeof (op_t); n -= sizeof (op_t))
+        *dst8++ = *src8++;
+
+      if (__builtin_expect (n == 0, 1))
+        return dstv;
+
+      final = *src8;
+    }
+
+  /* n != 0 if we get here.  Write out any trailing bytes. */
+  dst1 = (char *) dst8;
+#ifndef __BIG_ENDIAN__
+  if (n & 4)
+    {
+      *(uint32_t *) dst1 = final;
+      dst1 += 4;
+      final >>= 32;
+      n &= 3;
+    }
+  if (n & 2)
+    {
+      *(uint16_t *) dst1 = final;
+      dst1 += 2;
+      final >>= 16;
+      n &= 1;
+    }
+  if (n)
+    *(uint8_t *) dst1 = final;
+#else
+  if (n & 4)
+    {
+      *(uint32_t *) dst1 = final >> 32;
+      dst1 += 4;
+    }
+  else
+    {
+      final >>= 32;
+    }
+  if (n & 2)
+    {
+      *(uint16_t *) dst1 = final >> 16;
+      dst1 += 2;
+    }
+  else
+    {
+      final >>= 16;
+    }
+  if (n & 1)
+    *(uint8_t *) dst1 = final >> 8;
+#endif
+
+  return dstv;
+}
+weak_alias (__memcpy, memcpy)
+libc_hidden_builtin_def (memcpy)
diff --git a/sysdeps/tile/tilegx/memmove.c b/sysdeps/tile/tilegx/memmove.c
new file mode 100644
index 0000000000..38323cea3d
--- /dev/null
+++ b/sysdeps/tile/tilegx/memmove.c
@@ -0,0 +1,22 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied.  Overlap is handled correctly.
+   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* The tilegx implementation of memcpy is safe to use for memmove.  */
+#define MEMCPY_OK_FOR_FWD_MEMMOVE 1
+#include <string/memmove.c>
diff --git a/sysdeps/tile/tilegx/memset.c b/sysdeps/tile/tilegx/memset.c
new file mode 100644
index 0000000000..d41b205a3c
--- /dev/null
+++ b/sysdeps/tile/tilegx/memset.c
@@ -0,0 +1,151 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <arch/chip.h>
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+void *
+__memset (void *s, int c, size_t n)
+{
+  uint64_t *out64;
+  int n64, to_align64;
+  uint64_t v64;
+  uint8_t *out8 = s;
+
+  /* Experimentation shows that a trivial tight loop is a win up until
+     around a size of 20, where writing a word at a time starts to win.  */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 7
+  /* This must be at least at least this big, or some code later
+     on doesn't work.  */
+# error "BYTE_CUTOFF is too small."
+#endif
+
+  if (n < BYTE_CUTOFF)
+    {
+      /* Strangely, this turns out to be the tightest way to write
+         this loop.  */
+      if (n != 0)
+        {
+          do
+            {
+              /* Strangely, combining these into one line performs worse.  */
+              *out8 = c;
+              out8++;
+            }
+          while (--n != 0);
+        }
+
+      return s;
+    }
+
+  /* Align 'out8'. We know n >= 7 so this won't write past the end.  */
+  while (((uintptr_t) out8 & 7) != 0)
+    {
+      *out8++ = c;
+      --n;
+    }
+
+  /* Align 'n'. */
+  while (n & 7)
+    out8[--n] = c;
+
+  out64 = (uint64_t *) out8;
+  n64 = n >> 3;
+
+  /* Tile input byte out to 64 bits. */
+  v64 = copy_byte(c);
+
+  /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
+
+  /* Determine how many words we need to emit before the 'out32'
+     pointer becomes aligned modulo the cache line size.  */
+  to_align64 = (-((uintptr_t) out64 >> 3)) &
+    (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1);
+
+  /* Only bother aligning and using wh64 if there is at least
+     one full cache line to process.  This check also prevents
+     overrunning the end of the buffer with alignment words.  */
+  if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS)
+    {
+      int lines_left;
+
+      /* Align out64 mod the cache line size so we can use wh64. */
+      n64 -= to_align64;
+      for (; to_align64 != 0; to_align64--)
+        {
+          *out64 = v64;
+          out64++;
+        }
+
+      /* Use unsigned divide to turn this into a right shift. */
+      lines_left = (unsigned) n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+
+      do
+        {
+          /* Only wh64 a few lines at a time, so we don't exceed the
+             maximum number of victim lines.  */
+          int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS ()) ? lines_left
+                   : CHIP_MAX_OUTSTANDING_VICTIMS ());
+          uint64_t *wh = out64;
+          int i = x;
+          int j;
+
+          lines_left -= x;
+
+          do
+            {
+              __insn_wh64 (wh);
+              wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+            }
+          while (--i);
+
+          for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4); j != 0; j--)
+            {
+              *out64++ = v64;
+              *out64++ = v64;
+              *out64++ = v64;
+              *out64++ = v64;
+            }
+        }
+      while (lines_left != 0);
+
+      /* We processed all full lines above, so only this many
+         words remain to be processed.  */
+      n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1;
+    }
+
+  /* Now handle any leftover values. */
+  if (n64 != 0)
+    {
+      do
+        {
+          *out64 = v64;
+          out64++;
+        }
+      while (--n64 != 0);
+    }
+
+  return s;
+}
+weak_alias (__memset, memset)
+libc_hidden_builtin_def (memset)
diff --git a/sysdeps/tile/tilegx/memusage.h b/sysdeps/tile/tilegx/memusage.h
new file mode 100644
index 0000000000..7a9e661daf
--- /dev/null
+++ b/sysdeps/tile/tilegx/memusage.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+#include <arch/spr_def.h>
+
+#define GETSP() ({ register uintptr_t stack_ptr asm ("sp"); stack_ptr; })
+
+#define GETTIME(low,high)                       \
+  {                                             \
+    uint64_t cycles = __insn_mfspr (SPR_CYCLE); \
+    low = cycles & 0xffffffff;                  \
+    high = cycles >> 32;                        \
+  }
+
+#include <sysdeps/generic/memusage.h>
diff --git a/sysdeps/tile/tilegx/rawmemchr.c b/sysdeps/tile/tilegx/rawmemchr.c
new file mode 100644
index 0000000000..bd6d3c7c70
--- /dev/null
+++ b/sysdeps/tile/tilegx/rawmemchr.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+void *
+__rawmemchr (const void *s, int c)
+{
+  /* Get an aligned pointer. */
+  const uintptr_t s_int = (uintptr_t) s;
+  const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+  /* Create eight copies of the byte for which we are looking. */
+  const uint64_t goal = copy_byte(c);
+
+  /* Read the first word, but munge it so that bytes before the array
+     will not match goal.  */
+  const uint64_t before_mask = MASK (s_int);
+  uint64_t v = (*p | before_mask) ^ (goal & before_mask);
+
+  uint64_t bits;
+  while ((bits = __insn_v1cmpeq (v, goal)) == 0)
+    v = *++p;
+
+  return ((char *) p) + (CFZ (bits) >> 3);
+}
+libc_hidden_def (__rawmemchr)
+weak_alias (__rawmemchr, rawmemchr)
diff --git a/sysdeps/tile/tilegx/strchr.c b/sysdeps/tile/tilegx/strchr.c
new file mode 100644
index 0000000000..0ce73ce89d
--- /dev/null
+++ b/sysdeps/tile/tilegx/strchr.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+#undef strchr
+
+char *
+strchr (const char *s, int c)
+{
+  int z, g;
+
+  /* Get an aligned pointer. */
+  const uintptr_t s_int = (uintptr_t) s;
+  const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+  /* Create eight copies of the byte for which we are looking. */
+  const uint64_t goal = copy_byte(c);
+
+  /* Read the first aligned word, but force bytes before the string to
+     match neither zero nor goal (we make sure the high bit of each byte
+     is 1, and the low 7 bits are all the opposite of the goal byte).  */
+  const uint64_t before_mask = MASK (s_int);
+  uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+
+  uint64_t zero_matches, goal_matches;
+  while (1)
+    {
+      /* Look for a terminating '\0'. */
+      zero_matches = __insn_v1cmpeqi (v, 0);
+
+      /* Look for the goal byte. */
+      goal_matches = __insn_v1cmpeq (v, goal);
+
+      if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
+        break;
+
+      v = *++p;
+    }
+
+  z = CFZ (zero_matches);
+  g = CFZ (goal_matches);
+
+  /* If we found c before '\0' we got a match. Note that if c == '\0'
+     then g == z, and we correctly return the address of the '\0'
+     rather than NULL.  */
+  return (g <= z) ? ((char *) p) + (g >> 3) : NULL;
+}
+weak_alias (strchr, index)
+libc_hidden_builtin_def (strchr)
diff --git a/sysdeps/tile/tilegx/strchrnul.c b/sysdeps/tile/tilegx/strchrnul.c
new file mode 100644
index 0000000000..34c4317417
--- /dev/null
+++ b/sysdeps/tile/tilegx/strchrnul.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+char *
+__strchrnul (const char *s, int c)
+{
+  int z, g;
+
+  /* Get an aligned pointer. */
+  const uintptr_t s_int = (uintptr_t) s;
+  const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+  /* Create eight copies of the byte for which we are looking. */
+  const uint64_t goal = copy_byte(c);
+
+  /* Read the first aligned word, but force bytes before the string to
+     match neither zero nor goal (we make sure the high bit of each byte
+     is 1, and the low 7 bits are all the opposite of the goal byte).  */
+  const uint64_t before_mask = MASK (s_int);
+  uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+
+  uint64_t zero_matches, goal_matches;
+  while (1)
+    {
+      /* Look for a terminating '\0'. */
+      zero_matches = __insn_v1cmpeqi (v, 0);
+
+      /* Look for the goal byte. */
+      goal_matches = __insn_v1cmpeq (v, goal);
+
+      if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
+        break;
+
+      v = *++p;
+    }
+
+  z = CFZ (zero_matches);
+  g = CFZ (goal_matches);
+
+  /* Return a pointer to the NUL or goal, whichever is first. */
+  if (z < g)
+    g = z;
+  return ((char *) p) + (g >> 3);
+}
+weak_alias (__strchrnul, strchrnul)
diff --git a/sysdeps/tile/tilegx/string-endian.h b/sysdeps/tile/tilegx/string-endian.h
new file mode 100644
index 0000000000..0c4d51766d
--- /dev/null
+++ b/sysdeps/tile/tilegx/string-endian.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Provide a mask based on the pointer alignment that
+   sets up non-zero bytes before the beginning of the string.
+   The MASK expression works because shift counts are taken mod 64.
+   Also, specify how to count "first" and "last" bits
+   when the bits have been read as a word.  */
+
+#include <stdint.h>
+
+#ifndef __BIG_ENDIAN__
+#define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1)
+#define NULMASK(x) ((2ULL << x) - 1)
+#define CFZ(x) __insn_ctz(x)
+#define REVCZ(x) __insn_clz(x)
+#else
+#define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1)))
+#define NULMASK(x) (-2LL << (63 - x))
+#define CFZ(x) __insn_clz(x)
+#define REVCZ(x) __insn_ctz(x)
+#endif
+
+/* Create eight copies of the byte in a uint64_t. */
+static inline uint64_t copy_byte(uint8_t byte)
+{
+  uint64_t word = byte;
+  word = __insn_bfins(word, word, 8, 15);
+  word = __insn_bfins(word, word, 16, 31);
+  word = __insn_bfins(word, word, 32, 63);
+  return word;
+}
diff --git a/sysdeps/tile/tilegx/strlen.c b/sysdeps/tile/tilegx/strlen.c
new file mode 100644
index 0000000000..d0c06dc23e
--- /dev/null
+++ b/sysdeps/tile/tilegx/strlen.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+size_t
+strlen (const char *s)
+{
+  /* Get an aligned pointer. */
+  const uintptr_t s_int = (uintptr_t) s;
+  const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+  /* Read and MASK the first word. */
+  uint64_t v = *p | MASK (s_int);
+
+  uint64_t bits;
+  while ((bits = __insn_v1cmpeqi (v, 0)) == 0)
+    v = *++p;
+
+  return ((const char *) p) + (CFZ (bits) >> 3) - s;
+}
+libc_hidden_builtin_def (strlen)
diff --git a/sysdeps/tile/tilegx/strrchr.c b/sysdeps/tile/tilegx/strrchr.c
new file mode 100644
index 0000000000..f201cfa4fa
--- /dev/null
+++ b/sysdeps/tile/tilegx/strrchr.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+char *
+strrchr (const char *s, int c)
+{
+  /* Get an aligned pointer. */
+  const uintptr_t s_int = (uintptr_t) s;
+  const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+  /* Create eight copies of the byte for which we are looking. */
+  const uint64_t goal = copy_byte(c);
+
+  /* Read the first aligned word, but force bytes before the string to
+     match neither zero nor goal (we make sure the high bit of each byte
+     is 1, and the low 7 bits are all the opposite of the goal byte).  */
+  const uint64_t before_mask = MASK (s_int);
+  uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+  const char *found = NULL;
+  uint64_t zero_matches, goal_matches;
+  while (1)
+    {
+      /* Look for a terminating '\0'. */
+      zero_matches = __insn_v1cmpeqi (v, 0);
+
+      /* Look for the goal byte. */
+      goal_matches = __insn_v1cmpeq (v, goal);
+
+      /* If we found the goal, record the last offset. */
+      if (__builtin_expect (goal_matches != 0, 0))
+        {
+          if (__builtin_expect (zero_matches != 0, 0))
+            {
+              /* Clear any goal after the first zero. */
+              int first_nul = CFZ (zero_matches);
+              goal_matches &= NULMASK (first_nul);
+            }
+          if (__builtin_expect (goal_matches != 0, 1))
+            found = ((char *) p) + 7 - (REVCZ (goal_matches) >> 3);
+        }
+
+      if (__builtin_expect (zero_matches != 0, 0))
+        return (char *) found;
+
+      v = *++p;
+    }
+}
+weak_alias (strrchr, rindex)
+libc_hidden_builtin_def (strrchr)
diff --git a/sysdeps/tile/tilegx/tilegx32/Implies b/sysdeps/tile/tilegx/tilegx32/Implies
new file mode 100644
index 0000000000..993b7f4cd1
--- /dev/null
+++ b/sysdeps/tile/tilegx/tilegx32/Implies
@@ -0,0 +1,3 @@
+tile/tilegx
+tile
+wordsize-32
diff --git a/sysdeps/tile/tilegx/tilegx64/Implies b/sysdeps/tile/tilegx/tilegx64/Implies
new file mode 100644
index 0000000000..eb0686e0e6
--- /dev/null
+++ b/sysdeps/tile/tilegx/tilegx64/Implies
@@ -0,0 +1,3 @@
+tile/tilegx
+tile
+wordsize-64