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