// -*- c -*- // // %CopyrightBegin% // // Copyright Ericsson AB 2017. 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% // i_select_val_bins := select_val_bins.fetch.select; select_val_bins.head() { Eterm select_val; } select_val_bins.fetch(Src) { select_val = $Src; } select_val_bins.select(Fail, NumElements) { struct Pairs { BeamInstr val; BeamInstr* addr; }; struct Pairs* low; struct Pairs* high; struct Pairs* mid; int bdiff; /* int not long because the arrays aren't that large */ low = (struct Pairs *) (&$NumElements + 1); high = low + $NumElements; /* The pointer subtraction (high-low) below must produce * a signed result, because high could be < low. That * requires the compiler to insert quite a bit of code. * * However, high will be > low so the result will be * positive. We can use that knowledge to optimise the * entire sequence, from the initial comparison to the * computation of mid. * * -- Mikael Pettersson, Acumem AB * * Original loop control code: * * while (low < high) { * mid = low + (high-low) / 2; * */ while ((bdiff = (int)((char*)high - (char*)low)) > 0) { unsigned int boffset = ((unsigned int)bdiff >> 1) & ~(sizeof(struct Pairs)-1); mid = (struct Pairs*)((char*)low + boffset); if (select_val < mid->val) { high = mid; } else if (select_val > mid->val) { low = mid + 1; } else { $NEXT(mid->addr); } } $NEXT($Fail); } i_select_tuple_arity2 := select_val2.src.ta_fail.execute; i_select_val2 := select_val2.src.fail.execute; select_val2.head() { Eterm select_val2; BeamInstr* select_fail; } select_val2.src(Src) { select_val2 = $Src; } select_val2.ta_fail(Fail) { select_fail = &$Fail; if (is_not_tuple(select_val2)) { $FAIL(*select_fail); } select_val2 = *tuple_val(select_val2); } select_val2.fail(Fail) { select_fail = &$Fail; } select_val2.execute(T1, T2, D1, D2) { if (select_val2 == $T1) { $JUMP($D1); } else if (select_val2 == $T2) { $JUMP($D2); } else { $FAIL(*select_fail); } } i_select_tuple_arity := select_val_lin.fetch.ta_fail.execute; i_select_val_lins := select_val_lin.fetch.fail.execute; select_val_lin.head() { Eterm select_val; BeamInstr* select_fail; } select_val_lin.fetch(Src) { select_val = $Src; } select_val_lin.ta_fail(Fail) { select_fail = &$Fail; if (is_tuple(select_val)) { select_val = *tuple_val(select_val); } else { $JUMP(*select_fail); } } select_val_lin.fail(Fail) { select_fail = &$Fail; } select_val_lin.execute(N) { BeamInstr* vs = $NEXT_INSTRUCTION; int ix = 0; for (;;) { if (vs[ix+0] >= select_val) { ix += 0; break; } if (vs[ix+1] >= select_val) { ix += 1; break; } ix += 2; } if (vs[ix] == select_val) { I = $NEXT_INSTRUCTION + $N + ix; $JUMP(*I); } else { $JUMP(*select_fail); } } JUMP_ON_VAL(Fail, Index, N, Base) { if (is_small($Index)) { $Index = (Uint) (signed_val($Index) - $Base); if ($Index < $N) { $JUMP((($NEXT_INSTRUCTION)[$Index])); } } $FAIL($Fail); } i_jump_on_val_zero := jump_on_val_zero.fetch.execute; jump_on_val_zero.head() { Eterm index; } jump_on_val_zero.fetch(Src) { index = $Src; } jump_on_val_zero.execute(Fail, N) { $JUMP_ON_VAL($Fail, index, $N, 0); } i_jump_on_val := jump_on_val.fetch.execute; jump_on_val.head() { Eterm index; } jump_on_val.fetch(Src) { index = $Src; } jump_on_val.execute(Fail, N, Base) { $JUMP_ON_VAL($Fail, index, $N, $Base); }