GC_push_thread_structures ()
{
  GC_push_all (&GC_threads, &MEM[(void *)&GC_threads + 512B]);
}


GC_new_thread (pthread_t id)
{
  int id.0;
  int first_thread_used.1;
  struct GC_Thread_Rep * D.8640;
  struct GC_Thread_Rep * D.8641;
  int hv;
  struct GC_Thread_Rep * result;
  static GC_bool first_thread_used = 0;

  id.0 = (int) id;
  hv = id.0 & 127;
  first_thread_used.1 = first_thread_used;
  if (first_thread_used.1 == 0) goto <D.8635>; else goto <D.8636>;
  <D.8635>:
  result = &first_thread;
  first_thread_used = 1;
  goto <D.8637>;
  <D.8636>:
  result = GC_generic_malloc_inner (48, 1);
  <D.8637>:
  if (result == 0B) goto <D.8638>; else goto <D.8639>;
  <D.8638>:
  D.8640 = 0B;
  return D.8640;
  <D.8639>:
  result->id = id;
  D.8641 = GC_threads[hv];
  result->next = D.8641;
  GC_threads[hv] = result;
  D.8640 = result;
  return D.8640;
}


GC_delete_thread (pthread_t id)
{
  int id.2;
  long unsigned int D.8644;
  int D.8645;
  struct GC_Thread_Rep * D.8648;
  int hv;
  register struct GC_Thread_Rep * p;
  register struct GC_Thread_Rep * prev;

  id.2 = (int) id;
  hv = id.2 & 127;
  p = GC_threads[hv];
  prev = 0B;
  goto <D.8466>;
  <D.8465>:
  prev = p;
  p = p->next;
  <D.8466>:
  D.8644 = p->id;
  D.8645 = pthread_equal (D.8644, id);
  if (D.8645 == 0) goto <D.8465>; else goto <D.8467>;
  <D.8467>:
  if (prev == 0B) goto <D.8646>; else goto <D.8647>;
  <D.8646>:
  D.8648 = p->next;
  GC_threads[hv] = D.8648;
  goto <D.8649>;
  <D.8647>:
  D.8648 = p->next;
  prev->next = D.8648;
  <D.8649>:
  GC_free_inner (p);
}


pthread_equal (pthread_t __thread1, pthread_t __thread2)
{
  int D.8650;
  _Bool D.8651;

  D.8651 = __thread1 == __thread2;
  D.8650 = (int) D.8651;
  return D.8650;
}


GC_delete_gc_thread (pthread_t id, struct GC_Thread_Rep * gc_id)
{
  int id.3;
  struct GC_Thread_Rep * D.8656;
  int hv;
  register struct GC_Thread_Rep * p;
  register struct GC_Thread_Rep * prev;

  id.3 = (int) id;
  hv = id.3 & 127;
  p = GC_threads[hv];
  prev = 0B;
  goto <D.8476>;
  <D.8475>:
  prev = p;
  p = p->next;
  <D.8476>:
  if (p != gc_id) goto <D.8475>; else goto <D.8477>;
  <D.8477>:
  if (prev == 0B) goto <D.8654>; else goto <D.8655>;
  <D.8654>:
  D.8656 = p->next;
  GC_threads[hv] = D.8656;
  goto <D.8657>;
  <D.8655>:
  D.8656 = p->next;
  prev->next = D.8656;
  <D.8657>:
  GC_free_inner (p);
}


GC_lookup_thread (pthread_t id)
{
  int id.4;
  long unsigned int D.8660;
  int D.8661;
  struct GC_Thread_Rep * D.8662;
  int hv;
  register struct GC_Thread_Rep * p;

  id.4 = (int) id;
  hv = id.4 & 127;
  p = GC_threads[hv];
  goto <D.8484>;
  <D.8483>:
  p = p->next;
  <D.8484>:
  if (p != 0B) goto <D.8659>; else goto <D.8485>;
  <D.8659>:
  D.8660 = p->id;
  D.8661 = pthread_equal (D.8660, id);
  if (D.8661 == 0) goto <D.8483>; else goto <D.8485>;
  <D.8485>:
  D.8662 = p;
  return D.8662;
}


GC_thread_is_registered ()
{
  int D.8664;
  long unsigned int D.8667;
  int D.8668;
  _Bool D.8669;
  void * ptr;

  D.8664 = GC_test_and_set (&GC_allocate_lock);
  if (D.8664 != 0) goto <D.8665>; else goto <D.8666>;
  <D.8665>:
  GC_lock ();
  <D.8666>:
  D.8667 = pthread_self ();
  ptr = GC_lookup_thread (D.8667);
  GC_clear (&GC_allocate_lock);
  D.8669 = ptr != 0B;
  D.8668 = (int) D.8669;
  return D.8668;
}


GC_test_and_set (volatile unsigned int * addr)
{
  int D.8671;
  unsigned int D.8672;

  D.8672 = __sync_lock_test_and_set_4 (addr, 1);
  D.8671 = (int) D.8672;
  return D.8671;
}


GC_clear (volatile unsigned int * addr)
{
  __sync_synchronize ();
  *addr = 0;
}


GC_register_altstack (void * stack, int stack_size, void * altstack, int altstack_size)
{
  int D.8674;
  long unsigned int main_pthread_self.5;
  struct GC_Thread_Rep * thread;

  D.8674 = GC_test_and_set (&GC_allocate_lock);
  if (D.8674 != 0) goto <D.8675>; else goto <D.8676>;
  <D.8675>:
  GC_lock ();
  <D.8676>:
  main_pthread_self.5 = pthread_self ();
  thread = GC_lookup_thread (main_pthread_self.5);
  if (thread != 0B) goto <D.8678>; else goto <D.8679>;
  <D.8678>:
  thread->stack = stack;
  thread->stack_size = stack_size;
  thread->altstack = altstack;
  thread->altstack_size = altstack_size;
  goto <D.8680>;
  <D.8679>:
  main_pthread_self.5 = pthread_self ();
  main_pthread_self = main_pthread_self.5;
  main_stack = stack;
  main_stack_size = stack_size;
  main_altstack = altstack;
  main_altstack_size = altstack_size;
  <D.8680>:
  GC_clear (&GC_allocate_lock);
}


GC_get_nprocs ()
{
  int D.8684;
  void (*<Tdd1>) (char *, GC_word) GC_current_warn_proc.6;
  int D.8686;
  char D.8687;
  unsigned int D.8690;
  char D.8691;
  unsigned int D.8694;
  char D.8695;
  unsigned int D.8698;
  char D.8699;
  sizetype D.8702;
  const char * D.8703;
  long unsigned int cpu_no.7;
  int D.8707;
  unsigned int D.8708;
  char stat_buf[4096];
  int f;
  word result;
  size_t i;
  size_t len;

  try
    {
      result = 1;
      len = 0;
      f = open ("/proc/stat", 0);
      if (f < 0) goto <D.8681>; else goto <D.8683>;
      <D.8683>:
      D.8684 = read (f, &stat_buf, 4096);
      len = (size_t) D.8684;
      if (len <= 99) goto <D.8681>; else goto <D.8682>;
      <D.8681>:
      GC_current_warn_proc.6 = GC_current_warn_proc;
      GC_current_warn_proc.6 ("GC Warning: Couldn\'t read /proc/stat\n", 0);
      D.8686 = -1;
      return D.8686;
      <D.8682>:
      i = 0;
      goto <D.8506>;
      <D.8505>:
      D.8687 = stat_buf[i];
      if (D.8687 == 10) goto <D.8688>; else goto <D.8689>;
      <D.8688>:
      D.8690 = i + 1;
      D.8691 = stat_buf[D.8690];
      if (D.8691 == 99) goto <D.8692>; else goto <D.8693>;
      <D.8692>:
      D.8694 = i + 2;
      D.8695 = stat_buf[D.8694];
      if (D.8695 == 112) goto <D.8696>; else goto <D.8697>;
      <D.8696>:
      D.8698 = i + 3;
      D.8699 = stat_buf[D.8698];
      if (D.8699 == 117) goto <D.8700>; else goto <D.8701>;
      <D.8700>:
      {
        int cpu_no;

        D.8702 = i + 4;
        D.8703 = &stat_buf + D.8702;
        cpu_no = atoi (D.8703);
        cpu_no.7 = (long unsigned int) cpu_no;
        if (cpu_no.7 >= result) goto <D.8705>; else goto <D.8706>;
        <D.8705>:
        D.8707 = cpu_no + 1;
        result = (word) D.8707;
        <D.8706>:
      }
      <D.8701>:
      <D.8697>:
      <D.8693>:
      <D.8689>:
      i = i + 1;
      <D.8506>:
      D.8708 = len + 4294967196;
      if (D.8708 > i) goto <D.8505>; else goto <D.8507>;
      <D.8507>:
      close (f);
      D.8686 = (int) result;
      return D.8686;
    }
  finally
    {
      stat_buf = {CLOBBER};
    }
}


open (const char * __path, int __oflag)
{
  int D.8711;
  int D.8714;
  int D.8719;
  int D.8721;
  int D.8722;
  int D.8725;
  int D.8726;

  D.8711 = __builtin_va_arg_pack_len ();
  if (D.8711 > 1) goto <D.8712>; else goto <D.8713>;
  <D.8712>:
  __open_too_many_args ();
  <D.8713>:
  D.8714 = __builtin_constant_p (__oflag);
  if (D.8714 != 0) goto <D.8715>; else goto <D.8716>;
  <D.8715>:
  D.8719 = __oflag & 64;
  if (D.8719 != 0) goto <D.8717>; else goto <D.8720>;
  <D.8720>:
  D.8721 = __oflag & 4210688;
  if (D.8721 == 4210688) goto <D.8717>; else goto <D.8718>;
  <D.8717>:
  D.8722 = __builtin_va_arg_pack_len ();
  if (D.8722 <= 0) goto <D.8723>; else goto <D.8724>;
  <D.8723>:
  __open_missing_mode ();
  D.8725 = __open_2 (__path, __oflag);
  return D.8725;
  <D.8724>:
  <D.8718>:
  D.8725 = __open_alias (__path, __oflag, __builtin_va_arg_pack ());
  return D.8725;
  <D.8716>:
  D.8726 = __builtin_va_arg_pack_len ();
  if (D.8726 <= 0) goto <D.8727>; else goto <D.8728>;
  <D.8727>:
  D.8725 = __open_2 (__path, __oflag);
  return D.8725;
  <D.8728>:
  D.8725 = __open_alias (__path, __oflag, __builtin_va_arg_pack ());
  return D.8725;
}


read (int __fd, void * __buf, size_t __nbytes)
{
  unsigned int D.8730;
  int D.8733;
  ssize_t D.8736;
  unsigned int D.8737;
  unsigned int D.8738;
  unsigned int D.8741;

  D.8730 = __builtin_object_size (__buf, 0);
  if (D.8730 != 4294967295) goto <D.8731>; else goto <D.8732>;
  <D.8731>:
  D.8733 = __builtin_constant_p (__nbytes);
  if (D.8733 == 0) goto <D.8734>; else goto <D.8735>;
  <D.8734>:
  D.8737 = __builtin_object_size (__buf, 0);
  D.8736 = __read_chk (__fd, __buf, __nbytes, D.8737);
  return D.8736;
  <D.8735>:
  D.8738 = __builtin_object_size (__buf, 0);
  if (D.8738 < __nbytes) goto <D.8739>; else goto <D.8740>;
  <D.8739>:
  D.8741 = __builtin_object_size (__buf, 0);
  D.8736 = __read_chk_warn (__fd, __buf, __nbytes, D.8741);
  return D.8736;
  <D.8740>:
  <D.8732>:
  D.8736 = __read_alias (__fd, __buf, __nbytes);
  return D.8736;
}


atoi (const char * __nptr)
{
  int D.8743;

  D.8743 = strtol (__nptr, 0B, 10);
  return D.8743;
}


GC_wait_for_gc_completion (GC_bool wait_for_all)
{
  int GC_incremental.8;
  int D.8748;
  long unsigned int GC_gc_no.9;
  int D.8752;
  int D.8756;
  long unsigned int old_gc_no.10;

  GC_incremental.8 = GC_incremental;
  if (GC_incremental.8 != 0) goto <D.8746>; else goto <D.8747>;
  <D.8746>:
  D.8748 = GC_collection_in_progress ();
  if (D.8748 != 0) goto <D.8749>; else goto <D.8750>;
  <D.8749>:
  {
    int old_gc_no;

    GC_gc_no.9 = GC_gc_no;
    old_gc_no = (int) GC_gc_no.9;
    goto <D.8514>;
    <D.8513>:
    GC_collecting = 1;
    GC_in_thread_creation = 1;
    GC_collect_a_little_inner (1);
    GC_in_thread_creation = 0;
    GC_collecting = 0;
    GC_clear (&GC_allocate_lock);
    sched_yield ();
    D.8752 = GC_test_and_set (&GC_allocate_lock);
    if (D.8752 != 0) goto <D.8753>; else goto <D.8754>;
    <D.8753>:
    GC_lock ();
    <D.8754>:
    <D.8514>:
    GC_incremental.8 = GC_incremental;
    if (GC_incremental.8 != 0) goto <D.8755>; else goto <D.8515>;
    <D.8755>:
    D.8756 = GC_collection_in_progress ();
    if (D.8756 != 0) goto <D.8757>; else goto <D.8515>;
    <D.8757>:
    if (wait_for_all != 0) goto <D.8513>; else goto <D.8758>;
    <D.8758>:
    old_gc_no.10 = (long unsigned int) old_gc_no;
    GC_gc_no.9 = GC_gc_no;
    if (old_gc_no.10 == GC_gc_no.9) goto <D.8513>; else goto <D.8515>;
    <D.8515>:
  }
  <D.8750>:
  <D.8747>:
}


GC_thr_init ()
{
  int GC_thr_initialized.11;
  long unsigned int D.8763;
  long unsigned int main_pthread_self.12;
  void * main_stack.13;
  int main_stack_size.14;
  void * main_altstack.15;
  int main_altstack_size.16;
  int GC_nprocs.17;
  long int GC_nprocs.18;
  int GC_nprocs.19;
  void (*<Tdd1>) (char *, GC_word) GC_current_warn_proc.20;
  long unsigned int GC_nprocs.21;
  int dummy;
  struct GC_Thread_Rep * t;

  try
    {
      GC_thr_initialized.11 = GC_thr_initialized;
      if (GC_thr_initialized.11 != 0) goto <D.8761>; else goto <D.8762>;
      <D.8761>:
      return;
      <D.8762>:
      GC_thr_initialized = 1;
      D.8763 = pthread_self ();
      t = GC_new_thread (D.8763);
      t->stop_info.stack_ptr = &dummy;
      t->flags = 6;
      D.8763 = pthread_self ();
      main_pthread_self.12 = main_pthread_self;
      if (D.8763 == main_pthread_self.12) goto <D.8765>; else goto <D.8766>;
      <D.8765>:
      main_stack.13 = main_stack;
      t->stack = main_stack.13;
      main_stack_size.14 = main_stack_size;
      t->stack_size = main_stack_size.14;
      main_altstack.15 = main_altstack;
      t->altstack = main_altstack.15;
      main_altstack_size.16 = main_altstack_size;
      t->altstack_size = main_altstack_size.16;
      <D.8766>:
      GC_stop_init ();
      {
        char * nprocs_string;

        nprocs_string = getenv ("GC_NPROCS");
        GC_nprocs = -1;
        if (nprocs_string != 0B) goto <D.8771>; else goto <D.8772>;
        <D.8771>:
        GC_nprocs.17 = atoi (nprocs_string);
        GC_nprocs = GC_nprocs.17;
        <D.8772>:
      }
      GC_nprocs.18 = GC_nprocs;
      if (GC_nprocs.18 <= 0) goto <D.8775>; else goto <D.8776>;
      <D.8775>:
      GC_nprocs.19 = GC_get_nprocs ();
      GC_nprocs = GC_nprocs.19;
      <D.8776>:
      GC_nprocs.18 = GC_nprocs;
      if (GC_nprocs.18 <= 0) goto <D.8778>; else goto <D.8779>;
      <D.8778>:
      GC_current_warn_proc.20 = GC_current_warn_proc;
      GC_nprocs.18 = GC_nprocs;
      GC_nprocs.21 = (long unsigned int) GC_nprocs.18;
      GC_current_warn_proc.20 ("GC Warning: GC_get_nprocs() returned %ld\n", GC_nprocs.21);
      GC_nprocs = 2;
      goto <D.8782>;
      <D.8779>:
      <D.8782>:
    }
  finally
    {
      dummy = {CLOBBER};
    }
}


GC_init_parallel ()
{
  int parallel_initialized.22;
  int GC_is_initialized.23;

  parallel_initialized.22 = parallel_initialized;
  if (parallel_initialized.22 != 0) goto <D.8787>; else goto <D.8788>;
  <D.8787>:
  return;
  <D.8788>:
  parallel_initialized = 1;
  GC_is_initialized.23 = GC_is_initialized;
  if (GC_is_initialized.23 == 0) goto <D.8790>; else goto <D.8791>;
  <D.8790>:
  GC_init ();
  <D.8791>:
}


GC_pthread_sigmask (int how, const struct sigset_t * set, struct sigset_t * oset)
{
  _Bool D.8795;
  _Bool D.8796;
  _Bool D.8797;
  int D.8800;
  struct sigset_t fudged_set;

  try
    {
      if (set != 0B) goto <D.8793>; else goto <D.8794>;
      <D.8793>:
      D.8795 = how == 0;
      D.8796 = how == 2;
      D.8797 = D.8795 | D.8796;
      if (D.8797 != 0) goto <D.8798>; else goto <D.8799>;
      <D.8798>:
      fudged_set = *set;
      sigdelset (&fudged_set, 30);
      set = &fudged_set;
      <D.8799>:
      <D.8794>:
      D.8800 = pthread_sigmask (how, set, oset);
      return D.8800;
    }
  finally
    {
      fudged_set = {CLOBBER};
    }
}


GC_start_blocking ()
{
  int D.8803;
  long unsigned int D.8806;
  char * D.8807;
  char * D.8808;
  char * D.8809;
  struct GC_Thread_Rep * me;

  D.8803 = GC_test_and_set (&GC_allocate_lock);
  if (D.8803 != 0) goto <D.8804>; else goto <D.8805>;
  <D.8804>:
  GC_lock ();
  <D.8805>:
  D.8806 = pthread_self ();
  me = GC_lookup_thread (D.8806);
  D.8807 = GC_approx_sp ();
  me->stop_info.stack_ptr = D.8807;
  D.8808 = me->stop_info.stack_ptr;
  D.8809 = D.8808 + 4294967168;
  me->stop_info.stack_ptr = D.8809;
  me->thread_blocked = 1;
  GC_clear (&GC_allocate_lock);
}


GC_end_blocking ()
{
  int D.8810;
  long unsigned int D.8813;
  struct GC_Thread_Rep * me;

  D.8810 = GC_test_and_set (&GC_allocate_lock);
  if (D.8810 != 0) goto <D.8811>; else goto <D.8812>;
  <D.8811>:
  GC_lock ();
  <D.8812>:
  D.8813 = pthread_self ();
  me = GC_lookup_thread (D.8813);
  me->thread_blocked = 0;
  GC_clear (&GC_allocate_lock);
}


GC_sleep (unsigned int seconds)
{
  unsigned int D.8814;
  int D.8815;
  int result;

  GC_start_blocking ();
  D.8814 = sleep (seconds);
  result = (int) D.8814;
  GC_end_blocking ();
  D.8815 = result;
  return D.8815;
}


GC_thread_exit_proc (void * arg)
{
  int D.8817;
  long unsigned int D.8820;
  short int D.8821;
  unsigned short D.8822;
  int D.8823;
  int D.8824;
  short int D.8828;
  struct GC_Thread_Rep * me;

  D.8817 = GC_test_and_set (&GC_allocate_lock);
  if (D.8817 != 0) goto <D.8818>; else goto <D.8819>;
  <D.8818>:
  GC_lock ();
  <D.8819>:
  D.8820 = pthread_self ();
  me = GC_lookup_thread (D.8820);
  D.8821 = me->flags;
  D.8822 = (unsigned short) D.8821;
  D.8823 = (int) D.8822;
  D.8824 = D.8823 & 2;
  if (D.8824 != 0) goto <D.8825>; else goto <D.8826>;
  <D.8825>:
  D.8820 = pthread_self ();
  GC_delete_thread (D.8820);
  goto <D.8827>;
  <D.8826>:
  D.8821 = me->flags;
  D.8828 = D.8821 | 1;
  me->flags = D.8828;
  <D.8827>:
  GC_wait_for_gc_completion (0);
  GC_clear (&GC_allocate_lock);
}


GC_pthread_join (pthread_t thread, void * * retval)
{
  int D.8829;
  int D.8834;
  int D.8837;
  int result;
  struct GC_Thread_Rep * thread_gc_id;

  D.8829 = GC_test_and_set (&GC_allocate_lock);
  if (D.8829 != 0) goto <D.8830>; else goto <D.8831>;
  <D.8830>:
  GC_lock ();
  <D.8831>:
  thread_gc_id = GC_lookup_thread (thread);
  GC_clear (&GC_allocate_lock);
  result = pthread_join (thread, retval);
  if (result == 0) goto <D.8832>; else goto <D.8833>;
  <D.8832>:
  D.8834 = GC_test_and_set (&GC_allocate_lock);
  if (D.8834 != 0) goto <D.8835>; else goto <D.8836>;
  <D.8835>:
  GC_lock ();
  <D.8836>:
  GC_delete_gc_thread (thread, thread_gc_id);
  GC_clear (&GC_allocate_lock);
  <D.8833>:
  D.8837 = result;
  return D.8837;
}


GC_pthread_detach (pthread_t thread)
{
  int D.8839;
  int D.8844;
  short int D.8847;
  short int D.8848;
  unsigned short D.8849;
  int D.8850;
  int D.8851;
  int D.8854;
  int result;
  struct GC_Thread_Rep * thread_gc_id;

  D.8839 = GC_test_and_set (&GC_allocate_lock);
  if (D.8839 != 0) goto <D.8840>; else goto <D.8841>;
  <D.8840>:
  GC_lock ();
  <D.8841>:
  thread_gc_id = GC_lookup_thread (thread);
  GC_clear (&GC_allocate_lock);
  result = pthread_detach (thread);
  if (result == 0) goto <D.8842>; else goto <D.8843>;
  <D.8842>:
  D.8844 = GC_test_and_set (&GC_allocate_lock);
  if (D.8844 != 0) goto <D.8845>; else goto <D.8846>;
  <D.8845>:
  GC_lock ();
  <D.8846>:
  D.8847 = thread_gc_id->flags;
  D.8848 = D.8847 | 2;
  thread_gc_id->flags = D.8848;
  D.8847 = thread_gc_id->flags;
  D.8849 = (unsigned short) D.8847;
  D.8850 = (int) D.8849;
  D.8851 = D.8850 & 1;
  if (D.8851 != 0) goto <D.8852>; else goto <D.8853>;
  <D.8852>:
  GC_delete_gc_thread (thread, thread_gc_id);
  <D.8853>:
  GC_clear (&GC_allocate_lock);
  <D.8843>:
  D.8854 = result;
  return D.8854;
}


GC_start_routine_head (void * arg, void * base_addr, void * (*ThreadStartFn) (void *) * start, void * * start_arg)
{
  int D.8856;
  long unsigned int D.8859;
  short int D.8860;
  long unsigned int GC_page_size.24;
  long unsigned int base_addr.25;
  long unsigned int D.8863;
  long unsigned int D.8864;
  long unsigned int D.8865;
  long unsigned int D.8866;
  char * D.8867;
  char * D.8868;
  char * D.8869;
  void * (*<Tddb>) (void *) D.8872;
  void * D.8875;
  long unsigned int D.8876;
  union sem_t * D.8879;
  void * D.8880;
  struct start_info * si;
  void * result;
  struct GC_Thread_Rep * me;
  pthread_t my_pthread;

  si = arg;
  my_pthread = pthread_self ();
  D.8856 = GC_test_and_set (&GC_allocate_lock);
  if (D.8856 != 0) goto <D.8857>; else goto <D.8858>;
  <D.8857>:
  GC_lock ();
  <D.8858>:
  GC_in_thread_creation = 1;
  me = GC_new_thread (my_pthread);
  GC_in_thread_creation = 0;
  me->stop_info.stack_ptr = 0B;
  D.8859 = si->flags;
  D.8860 = (short int) D.8859;
  me->flags = D.8860;
  GC_page_size.24 = GC_page_size;
  base_addr.25 = (long unsigned int) base_addr;
  D.8863 = GC_page_size.24 + base_addr.25;
  D.8864 = D.8863 + 4294967295;
  GC_page_size.24 = GC_page_size;
  D.8865 = -GC_page_size.24;
  D.8866 = D.8864 & D.8865;
  D.8867 = (char *) D.8866;
  me->stack_end = D.8867;
  D.8868 = me->stack_end;
  D.8869 = D.8868 + 4294967280;
  me->stop_info.stack_ptr = D.8869;
  GC_clear (&GC_allocate_lock);
  if (start != 0B) goto <D.8870>; else goto <D.8871>;
  <D.8870>:
  D.8872 = si->start_routine;
  *start = D.8872;
  <D.8871>:
  if (start_arg != 0B) goto <D.8873>; else goto <D.8874>;
  <D.8873>:
  D.8875 = si->arg;
  *start_arg = D.8875;
  <D.8874>:
  D.8859 = si->flags;
  D.8876 = D.8859 & 8;
  if (D.8876 == 0) goto <D.8877>; else goto <D.8878>;
  <D.8877>:
  D.8879 = &si->registered;
  sem_post (D.8879);
  <D.8878>:
  D.8880 = me;
  return D.8880;
}


GC_thread_register_foreign (void * base_addr)
{
  int parallel_initialized.26;
  int D.8885;
  int GC_thr_initialized.27;
  int D.8891;
  _Bool D.8892;
  struct start_info si;
  struct GC_Thread_Rep * me;

  try
    {
      si = {};
      si.flags = 8;
      parallel_initialized.26 = parallel_initialized;
      if (parallel_initialized.26 == 0) goto <D.8883>; else goto <D.8884>;
      <D.8883>:
      GC_init_parallel ();
      <D.8884>:
      D.8885 = GC_test_and_set (&GC_allocate_lock);
      if (D.8885 != 0) goto <D.8886>; else goto <D.8887>;
      <D.8886>:
      GC_lock ();
      <D.8887>:
      GC_thr_initialized.27 = GC_thr_initialized;
      if (GC_thr_initialized.27 == 0) goto <D.8889>; else goto <D.8890>;
      <D.8889>:
      GC_thr_init ();
      <D.8890>:
      GC_clear (&GC_allocate_lock);
      me = GC_start_routine_head (&si, base_addr, 0B, 0B);
      D.8892 = me != 0B;
      D.8891 = (int) D.8892;
      return D.8891;
    }
  finally
    {
      si = {CLOBBER};
    }
}


GC_start_routine (void * arg)
{
  long int D.8895;
  void * (*<Tddb>) (void *) start.28;
  void * start_arg.29;
  void * D.8902;
  int dummy;
  struct start_info * si;
  void * result;
  struct GC_Thread_Rep * me;
  void * (*ThreadStartFn) (void *) start;
  void * start_arg;

  try
    {
      si = arg;
      me = GC_start_routine_head (arg, &dummy, &start, &start_arg);
      {
        struct __pthread_unwind_buf_t __cancel_buf;
        void (*<Tc1>) (void *) __cancel_routine;
        void * __cancel_arg;
        int __not_first_call;

        try
          {
            __cancel_routine = GC_thread_exit_proc;
            __cancel_arg = 0B;
            __not_first_call = __sigsetjmp (&__cancel_buf.__cancel_jmp_buf, 0);
            D.8895 = __builtin_expect (__not_first_call, 0);
            if (D.8895 != 0) goto <D.8896>; else goto <D.8897>;
            <D.8896>:
            __cancel_routine (__cancel_arg);
            __pthread_unwind_next (&__cancel_buf);
            <D.8897>:
            __pthread_register_cancel (&__cancel_buf);
            start.28 = start;
            start_arg.29 = start_arg;
            result = start.28 (start_arg.29);
            me->status = result;
            __pthread_unregister_cancel (&__cancel_buf);
            if (1 != 0) goto <D.8900>; else goto <D.8901>;
            <D.8900>:
            __cancel_routine (__cancel_arg);
            <D.8901>:
          }
        finally
          {
            __cancel_buf = {CLOBBER};
          }
      }
      D.8902 = result;
      return D.8902;
    }
  finally
    {
      dummy = {CLOBBER};
      start = {CLOBBER};
      start_arg = {CLOBBER};
    }
}


GC_pthread_create (pthread_t * new_thread, const union pthread_attr_t * attr, void * (*<Tddb>) (void *) start_routine, void * arg)
{
  int D.8907;
  int parallel_initialized.30;
  int D.8915;
  union sem_t * D.8916;
  int D.8917;
  int GC_thr_initialized.31;
  int detachstate.32;
  int * D.8931;
  int D.8932;
  int D.8935;
  int D.8936;
  int result;
  int detachstate;
  word my_flags;
  struct start_info * si;

  try
    {
      my_flags = 0;
      D.8907 = GC_test_and_set (&GC_allocate_lock);
      if (D.8907 != 0) goto <D.8908>; else goto <D.8909>;
      <D.8908>:
      GC_lock ();
      <D.8909>:
      si = GC_generic_malloc_inner (28, 1);
      GC_clear (&GC_allocate_lock);
      parallel_initialized.30 = parallel_initialized;
      if (parallel_initialized.30 == 0) goto <D.8911>; else goto <D.8912>;
      <D.8911>:
      GC_init_parallel ();
      <D.8912>:
      if (si == 0B) goto <D.8913>; else goto <D.8914>;
      <D.8913>:
      D.8915 = 12;
      return D.8915;
      <D.8914>:
      D.8916 = &si->registered;
      sem_init (D.8916, 0, 0);
      si->start_routine = start_routine;
      si->arg = arg;
      D.8917 = GC_test_and_set (&GC_allocate_lock);
      if (D.8917 != 0) goto <D.8918>; else goto <D.8919>;
      <D.8918>:
      GC_lock ();
      <D.8919>:
      GC_thr_initialized.31 = GC_thr_initialized;
      if (GC_thr_initialized.31 == 0) goto <D.8921>; else goto <D.8922>;
      <D.8921>:
      GC_thr_init ();
      <D.8922>:
      if (attr == 0B) goto <D.8923>; else goto <D.8924>;
      <D.8923>:
      detachstate = 0;
      goto <D.8925>;
      <D.8924>:
      pthread_attr_getdetachstate (attr, &detachstate);
      <D.8925>:
      detachstate.32 = detachstate;
      if (detachstate.32 == 1) goto <D.8927>; else goto <D.8928>;
      <D.8927>:
      my_flags = my_flags | 2;
      <D.8928>:
      si->flags = my_flags;
      GC_clear (&GC_allocate_lock);
      result = pthread_create (new_thread, attr, GC_start_routine, si);
      if (result == 0) goto <D.8929>; else goto <D.8930>;
      <D.8929>:
      goto <D.8606>;
      <D.8605>:
      D.8931 = __errno_location ();
      D.8932 = *D.8931;
      if (D.8932 != 4) goto <D.8933>; else goto <D.8934>;
      <D.8933>:
      GC_abort ("sem_wait failed");
      <D.8934>:
      <D.8606>:
      D.8916 = &si->registered;
      D.8935 = sem_wait (D.8916);
      if (D.8935 != 0) goto <D.8605>; else goto <D.8607>;
      <D.8607>:
      <D.8930>:
      D.8916 = &si->registered;
      sem_destroy (D.8916);
      D.8936 = GC_test_and_set (&GC_allocate_lock);
      if (D.8936 != 0) goto <D.8937>; else goto <D.8938>;
      <D.8937>:
      GC_lock ();
      <D.8938>:
      GC_free_inner (si);
      GC_clear (&GC_allocate_lock);
      D.8915 = result;
      return D.8915;
    }
  finally
    {
      detachstate = {CLOBBER};
    }
}


GC_pause ()
{
  int i;

  i = 0;
  goto <D.8612>;
  <D.8611>:
  __asm__ __volatile__(" " :  :  : "memory");
  i = i + 1;
  <D.8612>:
  if (i <= 9) goto <D.8611>; else goto <D.8613>;
  <D.8613>:
}


GC_lock ()
{
  int D.8941;
  int GC_collecting.33;
  long int GC_nprocs.34;
  unsigned int i.35;
  unsigned int D.8951;
  unsigned int GC_allocate_lock.36;
  int D.8954;
  int D.8957;
  int D.8965;
  static unsigned int spin_max = 30;
  unsigned int my_spin_max;
  static unsigned int last_spins = 0;
  unsigned int my_last_spins;
  int i;
  void yield = <<< error >>>;

  D.8941 = GC_test_and_set (&GC_allocate_lock);
  if (D.8941 == 0) goto <D.8942>; else goto <D.8943>;
  <D.8942>:
  return;
  <D.8943>:
  my_spin_max = spin_max;
  my_last_spins = last_spins;
  i = 0;
  goto <D.8626>;
  <D.8625>:
  GC_collecting.33 = GC_collecting;
  if (GC_collecting.33 != 0) goto yield; else goto <D.8945>;
  <D.8945>:
  GC_nprocs.34 = GC_nprocs;
  if (GC_nprocs.34 == 1) goto yield; else goto <D.8947>;
  <D.8947>:
  i.35 = (unsigned int) i;
  D.8951 = my_last_spins / 2;
  if (i.35 < D.8951) goto <D.8948>; else goto <D.8952>;
  <D.8952>:
  GC_allocate_lock.36 = GC_allocate_lock;
  if (GC_allocate_lock.36 != 0) goto <D.8948>; else goto <D.8949>;
  <D.8948>:
  GC_pause ();
  // predicted unlikely by continue predictor.
  goto <D.8624>;
  <D.8949>:
  D.8954 = GC_test_and_set (&GC_allocate_lock);
  if (D.8954 == 0) goto <D.8955>; else goto <D.8956>;
  <D.8955>:
  i.35 = (unsigned int) i;
  last_spins = i.35;
  spin_max = 128;
  return;
  <D.8956>:
  <D.8624>:
  i = i + 1;
  <D.8626>:
  i.35 = (unsigned int) i;
  if (i.35 < my_spin_max) goto <D.8625>; else goto <D.8627>;
  <D.8627>:
  spin_max = 30;
  yield:
  i = 0;
  <D.8629>:
  D.8957 = GC_test_and_set (&GC_allocate_lock);
  if (D.8957 == 0) goto <D.8958>; else goto <D.8959>;
  <D.8958>:
  return;
  <D.8959>:
  if (i <= 11) goto <D.8960>; else goto <D.8961>;
  <D.8960>:
  sched_yield ();
  goto <D.8962>;
  <D.8961>:
  {
    struct timespec ts;

    try
      {
        if (i > 24) goto <D.8963>; else goto <D.8964>;
        <D.8963>:
        i = 24;
        <D.8964>:
        ts.tv_sec = 0;
        D.8965 = 1 << i;
        ts.tv_nsec = D.8965;
        nanosleep (&ts, 0B);
      }
    finally
      {
        ts = {CLOBBER};
      }
  }
  <D.8962>:
  i = i + 1;
  goto <D.8629>;
}


