1// -*- c -*-
2//
3// %CopyrightBegin%
4//
5// Copyright Ericsson AB 2017. All Rights Reserved.
6//
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11//     http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18//
19// %CopyrightEnd%
20//
21
22i_select_val_bins := select_val_bins.fetch.select;
23
24select_val_bins.head() {
25    Eterm select_val;
26}
27
28select_val_bins.fetch(Src) {
29    select_val = $Src;
30}
31
32select_val_bins.select(Fail, NumElements) {
33    struct Singleton {
34        BeamInstr val;
35    };
36    struct Singleton* low;
37    struct Singleton* high;
38    struct Singleton* mid;
39    int bdiff; /* int not long because the arrays aren't that large */
40
41    low = (struct Singleton *) ($NEXT_INSTRUCTION);
42    high = low + $NumElements;
43
44    /* The pointer subtraction (high-low) below must produce
45     * a signed result, because high could be < low. That
46     * requires the compiler to insert quite a bit of code.
47     *
48     * However, high will be > low so the result will be
49     * positive. We can use that knowledge to optimise the
50     * entire sequence, from the initial comparison to the
51     * computation of mid.
52     *
53     * -- Mikael Pettersson, Acumem AB
54     *
55     * Original loop control code:
56     *
57     * while (low < high) {
58     *    mid = low + (high-low) / 2;
59     *
60     */
61    while ((bdiff = (int)((char*)high - (char*)low)) > 0) {
62        unsigned int boffset = ((unsigned int)bdiff >> 1) & ~(sizeof(struct Singleton)-1);
63
64        mid = (struct Singleton*)((char*)low + boffset);
65        if (select_val < mid->val) {
66            high = mid;
67        } else if (select_val > mid->val) {
68            low = mid + 1;
69        } else {
70            Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION + $NumElements);
71            Sint32 offset = jump_tab[mid - (struct Singleton *)($NEXT_INSTRUCTION)];
72            $JUMP(offset);
73        }
74    }
75    $JUMP($Fail);
76}
77
78i_select_tuple_arity2 := select_val2.src.get_arity.execute;
79i_select_val2 := select_val2.src.execute;
80
81select_val2.head() {
82    Eterm select_val2;
83}
84
85select_val2.src(Src) {
86    select_val2 = $Src;
87}
88
89select_val2.get_arity() {
90    if (ERTS_LIKELY(is_tuple(select_val2))) {
91        select_val2 = *tuple_val(select_val2);
92    } else {
93        select_val2 = NIL;
94    }
95}
96
97select_val2.execute(Fail, T1, T2) {
98    Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION);
99
100    if (select_val2 == $T1) {
101        $JUMP(jump_tab[0]);
102    } else if (select_val2 == $T2) {
103        $JUMP(jump_tab[1]);
104    } else {
105        $FAIL($Fail);
106    }
107}
108
109i_select_tuple_arity := select_val_lin.fetch.get_arity.execute;
110i_select_val_lins := select_val_lin.fetch.execute;
111
112select_val_lin.head() {
113    Eterm select_val;
114}
115
116select_val_lin.fetch(Src) {
117    select_val = $Src;
118}
119
120select_val_lin.get_arity() {
121    if (ERTS_LIKELY(is_tuple(select_val))) {
122        select_val = *tuple_val(select_val);
123    } else {
124        select_val = NIL;
125    }
126}
127
128select_val_lin.execute(Fail, N) {
129    BeamInstr* vs = $NEXT_INSTRUCTION;
130    int ix = 0;
131
132    for (;;) {
133        if (vs[ix+0] >= select_val) {
134            ix += 0;
135            break;
136        }
137        if (vs[ix+1] >= select_val) {
138            ix += 1;
139            break;
140        }
141        ix += 2;
142    }
143
144    if (vs[ix] == select_val) {
145        Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION + $N);
146        Eterm offset = jump_tab[ix];
147        $JUMP(offset);
148    } else {
149        $JUMP($Fail);
150    }
151}
152
153JUMP_ON_VAL(Fail, Index, N, Base) {
154    if (is_small($Index)) {
155        $Index = (Uint) (signed_val($Index) - $Base);
156        if ($Index < $N) {
157            Sint32* jump_tab = (Sint32 *) ($NEXT_INSTRUCTION);
158            $JUMP(jump_tab[$Index]);
159        }
160    }
161    $FAIL($Fail);
162}
163
164i_jump_on_val_zero := jump_on_val_zero.fetch.execute;
165
166jump_on_val_zero.head() {
167    Eterm index;
168}
169
170jump_on_val_zero.fetch(Src) {
171    index = $Src;
172}
173
174jump_on_val_zero.execute(Fail, N) {
175    $JUMP_ON_VAL($Fail, index, $N, 0);
176}
177
178i_jump_on_val := jump_on_val.fetch.execute;
179
180jump_on_val.head() {
181    Eterm index;
182}
183
184jump_on_val.fetch(Src) {
185    index = $Src;
186}
187
188jump_on_val.execute(Fail, N, Base) {
189    $JUMP_ON_VAL($Fail, index, $N, $Base);
190}
191