/*****************************************************************
 *        Failure                                                 *
 *****************************************************************/

#ifdef INDENT_CODE
{
#endif /* INDENT_CODE */

  /* trust_fail                       */
  BOp(trust_fail, e);
  {
    while (POP_CHOICE_POINT(B->cp_b)) {
      POP_EXECUTE();
    }
  }
#ifdef YAPOR
  {
    choiceptr cut_pt;
    cut_pt = B->cp_b;
    CUT_prune_to(cut_pt);
    B = cut_pt;
  }
#else
  B = B->cp_b;
#endif /* YAPOR */
  goto fail;
  ENDBOp();

#ifdef YAPOR
shared_fail:
  B = Get_LOCAL_top_cp();
  SET_BB(PROTECT_FROZEN_B(B));
  goto fail;
#endif /* YAPOR */

  /* fail                             */
  PBOp(op_fail, e);

  if (PP) {
    UNLOCK(PP->PELock);
    PP = NULL;
  }
#ifdef COROUTINING
  CACHE_Y_AS_ENV(YREG);
  check_stack(NoStackFail, HR);
  ENDCACHE_Y_AS_ENV();
#endif

fail : {
  register tr_fr_ptr pt0 = TR;
#if defined(YAPOR) || defined(THREADS)
  if (PP) {
    UNLOCK(PP->PELock);
    PP = NULL;
  }
#endif
  PREG = B->cp_ap;
  save_pc();
  CACHE_TR(B->cp_tr);
  PREFETCH_OP(PREG);
failloop:
  if (pt0 == S_TR) {
    SP = SP0;
#ifdef LOW_LEVEL_TRACER
    if (Yap_do_low_level_trace) {
      int go_on = true;
      yamop *ipc = PREG;

      while (go_on) {
        op_numbers opnum = Yap_op_from_opcode(ipc->opc);

        go_on = false;
        switch (opnum) {
#ifdef TABLING
        case _table_load_answer:
          low_level_trace(retry_table_loader, LOAD_CP(B)->cp_pred_entry, NULL);
          break;
        case _table_try_answer:
        case _table_retry_me:
        case _table_trust_me:
        case _table_retry:
        case _table_trust:
        case _table_completion:
#ifdef THREADS_CONSUMER_SHARING
        case _table_answer_resolution_completion:
#endif /* THREADS_CONSUMER_SHARING */
#ifdef DETERMINISTIC_TABLING
          if (IS_DET_GEN_CP(B))
            low_level_trace(retry_table_generator, DET_GEN_CP(B)->cp_pred_entry,
                            NULL);
          else
#endif /* DETERMINISTIC_TABLING */
            low_level_trace(retry_table_generator, GEN_CP(B)->cp_pred_entry,
                            (CELL *)(GEN_CP(B) + 1));
          break;
        case _table_answer_resolution:
          low_level_trace(retry_table_consumer, CONS_CP(B)->cp_pred_entry,
                          NULL);
          break;
        case _trie_trust_var:
        case _trie_retry_var:
        case _trie_trust_var_in_pair:
        case _trie_retry_var_in_pair:
        case _trie_trust_val:
        case _trie_retry_val:
        case _trie_trust_val_in_pair:
        case _trie_retry_val_in_pair:
        case _trie_trust_atom:
        case _trie_retry_atom:
        case _trie_trust_atom_in_pair:
        case _trie_retry_atom_in_pair:
        case _trie_trust_null:
        case _trie_retry_null:
        case _trie_trust_null_in_pair:
        case _trie_retry_null_in_pair:
        case _trie_trust_pair:
        case _trie_retry_pair:
        case _trie_trust_appl:
        case _trie_retry_appl:
        case _trie_trust_appl_in_pair:
        case _trie_retry_appl_in_pair:
        case _trie_trust_extension:
        case _trie_retry_extension:
        case _trie_trust_double:
        case _trie_retry_double:
        case _trie_trust_longint:
        case _trie_retry_longint:
        case _trie_trust_gterm:
        case _trie_retry_gterm:
          low_level_trace(retry_table_loader, UndefCode, NULL);
          break;
#endif /* TABLING */
        case _or_else:
        case _or_last:
          low_level_trace(retry_or, NULL, NULL);
          break;
        case _retry2:
        case _retry3:
        case _retry4:
          ipc = NEXTOP(ipc, l);
          go_on = true;
          break;
        case _jump:
          ipc = ipc->y_u.l.l;
          go_on = true;
          break;
        case _retry_c:
        case _retry_userc:
          low_level_trace(retry_pred, ipc->y_u.OtapFs.p, B->cp_args);
          break;
        case _retry_profiled:
        case _count_retry:
          ipc = NEXTOP(ipc, p);
          go_on = true;
          break;
        case _retry_me:
        case _trust_me:
        case _count_retry_me:
        case _count_trust_me:
        case _profiled_retry_me:
        case _profiled_trust_me:
        case _retry_and_mark:
        case _profiled_retry_and_mark:
        case _retry:
        case _trust:
          low_level_trace(retry_pred, ipc->y_u.Otapl.p, B->cp_args);
          break;
        case _try_logical:
        case _retry_logical:
        case _profiled_retry_logical:
        case _count_retry_logical:
        case _trust_logical:
        case _profiled_trust_logical:
        case _count_trust_logical:
          low_level_trace(retry_pred, ipc->y_u.OtILl.d->ClPred, B->cp_args);
          break;
        case _Nstop:
        case _Ystop:
          low_level_trace(retry_pred, NULL, B->cp_args);
          break;
        default:
          break;
        }
      }
    }
#endif /* LOW_LEVEL_TRACER */
#ifdef FROZEN_STACKS
#ifdef YAPOR_SBA
    if (pt0 < TR_FZ || pt0 > (ADDR)CurrentTrailTop + MinTrailGap)
#else
    if (pt0 < TR_FZ)
#endif /* YAPOR_SBA */
    {
      TR = TR_FZ;
      TRAIL_LINK(pt0);
    } else
#endif /* FROZEN_STACKS */
      RESTORE_TR();
    GONext();
  }
  BEGD(d1);
  d1 = TrailTerm(pt0 - 1);
  pt0--;
  if (IsVarTerm(d1)) {
#if defined(YAPOR_SBA) && defined(YAPOR)
    /* clean up the trail when we backtrack */
    if (Unsigned((Int)(d1) - (Int)(H_FZ)) >
        Unsigned((Int)(B_FZ) - (Int)(H_FZ))) {
      RESET_VARIABLE(STACK_TO_SBA(d1));
    } else
#endif
      /* normal variable */
      RESET_VARIABLE(d1);
    goto failloop;
  }
/* pointer to code space */
/* or updatable variable */
#if defined(TERM_EXTENSIONS) || defined(FROZEN_STACKS) ||                      \
    defined(MULTI_ASSIGNMENT_VARIABLES)
  if (IsPairTerm(d1))
#endif /* TERM_EXTENSIONS || FROZEN_STACKS || MULTI_ASSIGNMENT_VARIABLES */
  {
    register CELL flags;
    CELL *pt1 = RepPair(d1);
#ifdef LIMIT_TABLING
    if ((ADDR)pt1 == LOCAL_TrailBase) {
      sg_fr_ptr sg_fr = (sg_fr_ptr)TrailVal(pt0);
      TrailTerm(pt0) = AbsPair((CELL *)(pt0 - 1));
      SgFr_state(sg_fr)--; /* complete_in_use --> complete : compiled_in_use -->
                              compiled */
      insert_into_global_sg_fr_list(sg_fr);
      goto failloop;
    }
#endif               /* LIMIT_TABLING */
#ifdef FROZEN_STACKS /* TRAIL */
    /* avoid frozen segments */
    if (
#ifdef YAPOR_SBA
        (ADDR)pt1 >= HeapTop
#else
        IN_BETWEEN(LOCAL_TrailBase, pt1, (ADDR)CurrentTrailTop + MinTrailGap)
#endif /* YAPOR_SBA */
    ) {
      pt0 = (tr_fr_ptr)pt1;
      goto failloop;
    } else
#endif /* FROZEN_STACKS */
        if (IN_BETWEEN(H0, pt1, HR)) {
      if (IsAttVar(pt1)) {
        goto failloop;
      } else {
        TR = pt0;
        Yap_CleanOpaqueVariable(d1);

        goto failloop;
      }
    }
#ifdef FROZEN_STACKS /* TRAIL */
    /* don't reset frozen variables */
    if (pt0 < TR_FZ)
      goto failloop;
#endif
    flags = *pt1;
#if MULTIPLE_STACKS
    if (FlagOn(DBClMask, flags)) {
      DBRef dbr = DBStructFlagsToDBStruct(pt1);
      int erase;

      LOCK(dbr->lock);
      DEC_DBREF_COUNT(dbr);
      erase = (dbr->Flags & ErasedMask) && (dbr->ref_count == 0);
      UNLOCK(dbr->lock);
      if (erase) {
        saveregs();
        Yap_ErDBE(dbr);
        setregs();
      }
    } else {
      if (flags & LogUpdMask) {
        if (flags & IndexMask) {
          LogUpdIndex *cl = ClauseFlagsToLogUpdIndex(pt1);
          int erase;
#if PARALLEL_YAP
          PredEntry *ap = cl->ClPred;
#endif

          PELOCK(8, ap);
          DEC_CLREF_COUNT(cl);
          erase = (cl->ClFlags & ErasedMask) && !(cl->ClRefCount);
          if (erase) {
            saveregs();
            /* at this point,
we are the only ones accessing the clause,
hence we don't need to have a lock it */
            Yap_ErLogUpdIndex(cl);
            setregs();
          } else if (cl->ClFlags & DirtyMask) {
            saveregs();
            /* at this point,
we are the only ones accessing the clause,
hence we don't need to have a lock it */
            Yap_CleanUpIndex(cl);
            setregs();
          }
          UNLOCK(ap->PELock);
        } else {
          LogUpdClause *cl = ClauseFlagsToLogUpdClause(pt1);
          int erase;
#if PARALLEL_YAP
          PredEntry *ap = cl->ClPred;
#endif
          /* BB support */
          if (ap) {

            PELOCK(9, ap);
            DEC_CLREF_COUNT(cl);
            erase = (cl->ClFlags & ErasedMask) && !(cl->ClRefCount);
            if (erase) {
              saveregs();
              /* at this point,
we are the only ones accessing the clause,
hence we don't need to have a lock it */
              Yap_ErLogUpdCl(cl);
              setregs();
            }
            UNLOCK(ap->PELock);
          }
        }
      } else {
        DynamicClause *cl = ClauseFlagsToDynamicClause(pt1);
        int erase;

        LOCK(cl->ClLock);
        DEC_CLREF_COUNT(cl);
        erase = (cl->ClFlags & ErasedMask) && !(cl->ClRefCount);
        UNLOCK(cl->ClLock);
        if (erase) {
          saveregs();
          /* at this point,
we are the only ones accessing the clause,
hence we don't need to have a lock it */
          Yap_ErCl(cl);
          setregs();
        }
      }
    }
#else
    ResetFlag(InUseMask, flags);
    *pt1 = flags;
    if (FlagOn((ErasedMask | DirtyMask), flags)) {
      if (FlagOn(DBClMask, flags)) {
        saveregs();
        Yap_ErDBE(DBStructFlagsToDBStruct(pt1));
        setregs();
      } else {
        saveregs();
        if (flags & LogUpdMask) {
          if (flags & IndexMask) {
            if (FlagOn(ErasedMask, flags)) {
              Yap_ErLogUpdIndex(ClauseFlagsToLogUpdIndex(pt1));
            } else {
              Yap_CleanUpIndex(ClauseFlagsToLogUpdIndex(pt1));
            }
          } else {
            Yap_ErLogUpdCl(ClauseFlagsToLogUpdClause(pt1));
          }
        } else {
          Yap_ErCl(ClauseFlagsToDynamicClause(pt1));
        }
        setregs();
      }
    }
#endif
    goto failloop;
  }
#ifdef MULTI_ASSIGNMENT_VARIABLES
  else /* if (IsApplTerm(d1)) */
  {
    CELL *pt = RepAppl(d1);
/* AbsAppl means */
/* multi-assignment variable */
/* so the next cell is the old value */
#ifdef FROZEN_STACKS
    --pt0;
    pt[0] = TrailVal(pt0);
#else
    pt[0] = TrailTerm(pt0 - 1);
    pt0 -= 2;
#endif /* FROZEN_STACKS */
    goto failloop;
  }
#endif
  ENDD(d1);
  ENDCACHE_TR();
}

#ifdef COROUTINING
NoStackFail:
  BEGD(d0);
#ifdef SHADOW_S
  Yap_REGS.S_ = SREG;
#endif
  saveregs();
  d0 = interrupt_fail(PASS_REGS1);
  setregs();
#ifdef SHADOW_S
  SREG = Yap_REGS.S_;
#endif
  if (!d0)
    FAIL();
  JMPNext();
  ENDD(d0);

#endif /* COROUTINING */
  ENDPBOp();
#ifdef INDENT_CODE
}
#endif /* INDENT_CODE */