text: // -*- c -*-
  //
  // %CopyrightBegin%
  //
  // Copyright Ericsson AB 2020. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //
  // %CopyrightEnd%
  //
  
  pred.is_offset(X, Y, Offset) {
      return X.type == Y.type && X.val + Offset == Y.val;
  }
  
  
  pred.succ(X, Y) {
      return X.type == Y.type && X.val + 1 == Y.val;
  }
  
  pred.succ3(X, Y) {
      return X.type == Y.type && X.val + 3 == Y.val;
  }
  
  pred.succ4(X, Y) {
      return X.type == Y.type && X.val + 4 == Y.val;
  }
  
  pred.never() {
      return 0;
  }
  
  pred.compiled_with_otp_20_or_higher() {
      return S->otp_20_or_higher;
  }
  
  // Test whether the following two moves are independent:
  //
  //    move Src1 Dst1
  //    move Src2 Dst2
  //
  pred.independent_moves(Src1, Dst1, Src2, Dst2) {
      return (Src1.type != Dst2.type || Src1.val != Dst2.val) &&
          (Src2.type != Dst1.type || Src2.val != Dst1.val) &&
          (Dst1.type != Dst2.type ||Dst1.val != Dst2.val);
  }
  
  
  // Test that the two registers are distinct.
  pred.distinct(Reg1, Reg2) {
      return Reg1.type != Reg2.type || Reg1.val != Reg2.val;
  }
  
  // Test whether a jump table can be used.
  pred.use_jump_tab(Size, Rest) {
      Sint min, max;
      Sint i;
  
      if (Size.val < 2 || Size.val % 2 != 0) {
          return 0;
      }
  
      if (Rest[0].type != TAG_i || Rest[1].type != TAG_f) {
          /* Atoms. Can't use a jump table. */
          return 0;
      }
  
      min = max = Rest[0].val;
      for (i = 2; i < Size.val; i += 2) {
          if (Rest[i].type != TAG_i || Rest[i+1].type != TAG_f) {
              return 0;
          }
          if (Rest[i].val < min) {
              min = Rest[i].val;
          } else if (max < Rest[i].val) {
              max = Rest[i].val;
          }
      }
  
      return max - min <= Size.val;
  }
  
  // Test whether all values in a table are either floats or bignums.
  pred.floats_or_bignums(Size, Rest) {
      int i;
  
      if (Size.val < 2 || Size.val % 2 != 0) {
          return 0;
      }
  
      for (i = 0; i < Size.val; i += 2) {
          if (Rest[i].type != TAG_q) {
              return 0;
          }
          if (Rest[i+1].type != TAG_f) {
              return 0;
          }
      }
  
      return 1;
  }
  
  
  // Test whether all values in a table have a fixed size.
  pred.fixed_size_values(Size, Rest) {
      int i;
  
      if (Size.val < 2 || Size.val % 2 != 0) {
          return 0;
      }
  
      for (i = 0; i < Size.val; i += 2) {
          if (Rest[i+1].type != TAG_f) {
              return 0;
          }
          switch (Rest[i].type) {
          case TAG_a:
          case TAG_i:
          case TAG_v:
              break;
          case TAG_q:
              return is_float(S->literals[Rest[i].val].term);
          default:
              return 0;
          }
      }
  
      return 1;
  }
  
  // Test whether a table has mixe types.
  pred.mixed_types(Size, Rest) {
      int i;
      Uint type;
  
      if (Size.val < 2 || Size.val % 2 != 0) {
          return 0;
      }
  
      type = Rest[0].type;
      for (i = 0; i < Size.val; i += 2) {
          if (Rest[i].type != type) {
              return 1;
          }
      }
  
      return 0;
  }
  
  // Test whether register Reg is killed by a make_fun instruction that
  // creates the fun given by index idx.
  pred.is_killed_by_make_fun(Reg, idx) {
      Uint num_free;
  
      if (idx.val >= S->num_lambdas) {
          /* Invalid index. Ignore the error for now. */
          return 0;
      } else {
          num_free = S->lambdas[idx.val].num_free;
          return Reg.type == TAG_x && num_free <= Reg.val;
      }
  }
  
  // Test whether Bif is "heavy" and should always go through its export entry.
  pred.is_heavy_bif(Bif) {
      Export *ep;
  
      if (Bif.type != TAG_u || Bif.val >= S->num_imports) {
          return 0;
      }
  
      if ((ep = S->import[Bif.val].bif) != 0) {
          return bif_table[ep->bif_number].kind == BIF_KIND_HEAVY;
      }
  
      return 0;
  }
  
  // Test whether the given literal is a map.
  pred.literal_is_map(Lit) {
      Eterm term;
  
      ASSERT(Lit.type == TAG_q);
      term = S->literals[Lit.val].term;
      return is_map(term);
  }
  
  // Predicate to test whether all of the given new small map keys are literals
  pred.is_small_map_literal_keys(Size, Rest) {
      if (Size.val > MAP_SMALL_MAP_LIMIT) {
          return 0;
      }
  
      /*
       * Operations with non-literals have always only one key.
       */
      if (Size.val != 2) {
          return 1;
      }
  
      switch (Rest[0].type) {
      case TAG_a:
      case TAG_i:
      case TAG_n:
      case TAG_q:
          return 1;
      default:
          return 0;
      }
  }
  
  // Test whether the given literal is an empty map.
  pred.is_empty_map(Lit) {
      Eterm term;
  
      if (Lit.type != TAG_q) {
          return 0;
      }
      term = S->literals[Lit.val].term;
      return is_flatmap(term) && flatmap_get_size(flatmap_val(term)) == 0;
  }
  
  // Test whether a binary construction is too big.
  pred.binary_too_big(Size) {
      return Size.type == TAG_o ||
          (Size.type == TAG_u && ((Size.val >> (8*sizeof(Uint)-3)) != 0));
  }
  
  
  // Test whether the negation of the given number is small.
  pred.negation_is_small(Int) {
      /*
       * Check for the rare case of overflow in BeamInstr (UWord) -> Sint.
       * Cast to the correct type before using IS_SSMALL (Sint).
       */
      return Int.type == TAG_i &&
          !(Int.val & ~((((BeamInstr)1) << ((sizeof(Sint)*8)-1))-1)) &&
          IS_SSMALL(-((Sint)Int.val));
  }
  
  // Mark this label. Always succeeds.
  pred.smp_mark_target_label(L) {
      ASSERT(L.type == TAG_f);
      S->labels[L.val].looprec_targeted = 1;
      return 1;
  }
  
  // Test whether this label was targeted by a loop_rec/2 instruction.
  pred.smp_already_locked(L) {
      ASSERT(L.type == TAG_u);
      return S->labels[L.val].looprec_targeted;
  }
  
  
  // Sort map keys. Always succeeds unless the instruction contains
  // invalid map keys (in which case loading will fail).
  pred.map_key_sort(Size, Rest) {
      return beam_load_map_key_sort(S, Size, Rest);
  }
  