// -*- c -*- // // %CopyrightBegin% // // Copyright Ericsson AB 2020-2022. 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.never() { return 0; } // Test whether a jump table can be used. pred.use_jump_tab(Size, Rest, MinSize) { Sint min, max; Sint i; if (Size.val < 2 * MinSize || 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(beamfile_get_literal(&S->beam, Rest[i].val)); 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 Bif is "heavy" and should always go through its export entry. pred.is_heavy_bif(Bif) { BeamFile_ImportEntry *import; Export *export; if (Bif.type != TAG_u || Bif.val >= S->beam.imports.count) { return 0; } import = &S->beam.imports.entries[Bif.val]; export = erts_active_export_entry(import->module, import->function, import->arity); if (export->bif_number != -1) { return bif_table[export->bif_number].kind == BIF_KIND_HEAVY; } return 0; } // Predicate to test whether all of the given new small map keys are literals pred.is_small_map_literal_keys(Size, Rest) { Uint pair_count = Size.val / 2; if (pair_count > MAP_SMALL_MAP_LIMIT) { return 0; } /* * Operations with non-literals have always only one key. */ if (pair_count != 1) { 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 = beamfile_get_literal(&S->beam, Lit.val); 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); } // Test that two operands are distinct. pred.distinct(Val1, Val2) { if (Val1.type != Val2.type) { return 1; } else if (Val1.type == TAG_x || Val1.type == TAG_y) { /* We must not compare the type indices (if any). */ return (Val1.val & REG_MASK) != (Val2.val & REG_MASK); } else if (Val1.type == TAG_n) { /* NIL has no associated value. */ return 0; } else { return Val1.val != Val2.val; } } // Test that two operands are equal when disregarding types. Opposite of the // `distinct` predicate. pred.equal(Val1, Val2) { if (Val1.type != Val2.type) { return 0; } else if (Val1.type == TAG_x || Val1.type == TAG_y) { /* We must not compare the type indices (if any). */ return (Val1.val & REG_MASK) == (Val2.val & REG_MASK); } else if (Val1.type == TAG_n) { /* NIL has no associated value. */ return 1; } else { return Val1.val == Val2.val; } }