// -*- 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 Singleton {
BeamInstr val;
};
struct Singleton* low;
struct Singleton* high;
struct Singleton* mid;
int bdiff; /* int not long because the arrays aren't that large */
low = (struct Singleton *) ($NEXT_INSTRUCTION);
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 Singleton)-1);
mid = (struct Singleton*)((char*)low + boffset);
if (select_val < mid->val) {
high = mid;
} else if (select_val > mid->val) {
low = mid + 1;
} else {
Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION + $NumElements);
Sint32 offset = jump_tab[mid - (struct Singleton *)($NEXT_INSTRUCTION)];
$JUMP(offset);
}
}
$JUMP($Fail);
}
i_select_tuple_arity2 := select_val2.src.get_arity.execute;
i_select_val2 := select_val2.src.execute;
select_val2.head() {
Eterm select_val2;
}
select_val2.src(Src) {
select_val2 = $Src;
}
select_val2.get_arity() {
if (ERTS_LIKELY(is_tuple(select_val2))) {
select_val2 = *tuple_val(select_val2);
} else {
select_val2 = NIL;
}
}
select_val2.execute(Fail, T1, T2) {
Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION);
if (select_val2 == $T1) {
$JUMP(jump_tab[0]);
} else if (select_val2 == $T2) {
$JUMP(jump_tab[1]);
} else {
$FAIL($Fail);
}
}
i_select_tuple_arity := select_val_lin.fetch.get_arity.execute;
i_select_val_lins := select_val_lin.fetch.execute;
select_val_lin.head() {
Eterm select_val;
}
select_val_lin.fetch(Src) {
select_val = $Src;
}
select_val_lin.get_arity() {
if (ERTS_LIKELY(is_tuple(select_val))) {
select_val = *tuple_val(select_val);
} else {
select_val = NIL;
}
}
select_val_lin.execute(Fail, 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) {
Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION + $N);
Eterm offset = jump_tab[ix];
$JUMP(offset);
} else {
$JUMP($Fail);
}
}
JUMP_ON_VAL(Fail, Index, N, Base) {
if (is_small($Index)) {
$Index = (Uint) (signed_val($Index) - $Base);
if ($Index < $N) {
Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION);
$JUMP(jump_tab[$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);
}