| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/v8.h" |
| 6 |
| 7 #include "src/arguments.h" |
| 8 #include "src/base/macros.h" |
| 9 #include "src/conversions.h" |
| 10 #include "src/runtime/runtime-utils.h" |
| 11 |
| 12 // Implement Single Instruction Multiple Data (SIMD) operations as defined in |
| 13 // the SIMD.js draft spec: |
| 14 // http://littledan.github.io/simd.html |
| 15 |
| 16 #define NumberToFloat32x4Component NumberToFloat |
| 17 |
| 18 #define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \ |
| 19 RUNTIME_ASSERT(args[index]->IsSmi()); \ |
| 20 int name = args.smi_at(index); \ |
| 21 RUNTIME_ASSERT(name >= 0 && name < lanes); |
| 22 |
| 23 #define SIMD_CHECK_FUNCTION(type) \ |
| 24 RUNTIME_FUNCTION(Runtime_##type##Check) { \ |
| 25 HandleScope scope(isolate); \ |
| 26 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 27 return *a; \ |
| 28 } |
| 29 |
| 30 #define SIMD_EXTRACT_LANE_FUNCTION(type, lanes) \ |
| 31 RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ |
| 32 HandleScope scope(isolate); \ |
| 33 DCHECK(args.length() == 2); \ |
| 34 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 35 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ |
| 36 return *isolate->factory()->NewNumber(a->get_lane(lane)); \ |
| 37 } |
| 38 |
| 39 #define SIMD4_CREATE_FUNCTION(type) \ |
| 40 RUNTIME_FUNCTION(Runtime_Create##type) { \ |
| 41 HandleScope scope(isolate); \ |
| 42 DCHECK(args.length() == 4); \ |
| 43 CONVERT_NUMBER_ARG_HANDLE_CHECKED(w, 0); \ |
| 44 CONVERT_NUMBER_ARG_HANDLE_CHECKED(x, 1); \ |
| 45 CONVERT_NUMBER_ARG_HANDLE_CHECKED(y, 2); \ |
| 46 CONVERT_NUMBER_ARG_HANDLE_CHECKED(z, 3); \ |
| 47 return *isolate->factory()->NewFloat32x4( \ |
| 48 NumberTo##type##Component(*w), NumberTo##type##Component(*x), \ |
| 49 NumberTo##type##Component(*y), NumberTo##type##Component(*z)); \ |
| 50 } |
| 51 |
| 52 #define SIMD_CREATE_WRAPPER_FUNCTION(type) \ |
| 53 RUNTIME_FUNCTION(Runtime_New##type##Wrapper) { \ |
| 54 HandleScope scope(isolate); \ |
| 55 DCHECK(args.length() == 1); \ |
| 56 CONVERT_ARG_HANDLE_CHECKED(type, value, 0); \ |
| 57 return *Object::ToObject(isolate, value).ToHandleChecked(); \ |
| 58 } |
| 59 |
| 60 #define SIMD4_EXTRACT_LANE_FUNCTION(type) SIMD_EXTRACT_LANE_FUNCTION(type, 4) |
| 61 |
| 62 #define SIMD4_REPLACE_LANE_FUNCTION(type) \ |
| 63 RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ |
| 64 HandleScope scope(isolate); \ |
| 65 DCHECK(args.length() == 3); \ |
| 66 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 67 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 4); \ |
| 68 CONVERT_NUMBER_ARG_HANDLE_CHECKED(replacement, 2); \ |
| 69 Handle<type> result = isolate->factory()->New##type( \ |
| 70 a->get_lane(0), a->get_lane(1), a->get_lane(2), a->get_lane(3)); \ |
| 71 result->set_lane(lane, NumberTo##type##Component(*replacement)); \ |
| 72 return *result; \ |
| 73 } |
| 74 |
| 75 #define SIMD4_UNARY_OP(type, a, op, result) \ |
| 76 DCHECK(args.length() == 1); \ |
| 77 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 78 Handle<type> result = \ |
| 79 isolate->factory()->New##type(op(a->get_lane(0)), op(a->get_lane(1)), \ |
| 80 op(a->get_lane(2)), op(a->get_lane(3))); |
| 81 |
| 82 #define SIMD4_ABS_FUNCTION(type) \ |
| 83 RUNTIME_FUNCTION(Runtime_##type##Abs) { \ |
| 84 HandleScope scope(isolate); \ |
| 85 SIMD4_UNARY_OP(type, a, std::abs, result); \ |
| 86 return *result; \ |
| 87 } |
| 88 |
| 89 #define SIMD4_NEG_FUNCTION(type) \ |
| 90 RUNTIME_FUNCTION(Runtime_##type##Neg) { \ |
| 91 HandleScope scope(isolate); \ |
| 92 SIMD4_UNARY_OP(type, a, -, result); \ |
| 93 return *result; \ |
| 94 } |
| 95 |
| 96 #define SIMD4_SQRT_FUNCTION(type) \ |
| 97 RUNTIME_FUNCTION(Runtime_##type##Sqrt) { \ |
| 98 HandleScope scope(isolate); \ |
| 99 SIMD4_UNARY_OP(type, a, std::sqrt, result); \ |
| 100 return *result; \ |
| 101 } |
| 102 |
| 103 #define SIMD4_RECIP_APPROX_FUNCTION(type) \ |
| 104 RUNTIME_FUNCTION(Runtime_##type##RecipApprox) { \ |
| 105 HandleScope scope(isolate); \ |
| 106 SIMD4_UNARY_OP(type, a, RecipApprox, result); \ |
| 107 return *result; \ |
| 108 } |
| 109 |
| 110 #define SIMD4_RECIP_SQRT_APPROX_FUNCTION(type) \ |
| 111 RUNTIME_FUNCTION(Runtime_##type##RecipSqrtApprox) { \ |
| 112 HandleScope scope(isolate); \ |
| 113 SIMD4_UNARY_OP(type, a, RecipSqrtApprox, result); \ |
| 114 return *result; \ |
| 115 } |
| 116 |
| 117 #define SIMD4_BINARY_OP(type, a, b, op, result) \ |
| 118 DCHECK(args.length() == 2); \ |
| 119 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 120 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 121 Handle<type> result = isolate->factory()->New##type( \ |
| 122 op(a->get_lane(0), b->get_lane(0)), op(a->get_lane(1), b->get_lane(1)), \ |
| 123 op(a->get_lane(2), b->get_lane(2)), op(a->get_lane(3), b->get_lane(3))); |
| 124 |
| 125 // Macros to make infix arithmetic operators look like f(a, b). |
| 126 #define BINARY_ADD(a, b) (a) + (b) |
| 127 #define BINARY_SUB(a, b) (a) - (b) |
| 128 #define BINARY_MUL(a, b) (a) * (b) |
| 129 #define BINARY_DIV(a, b) (a) / (b) |
| 130 |
| 131 #define SIMD4_ADD_FUNCTION(type) \ |
| 132 RUNTIME_FUNCTION(Runtime_##type##Add) { \ |
| 133 HandleScope scope(isolate); \ |
| 134 SIMD4_BINARY_OP(type, a, b, BINARY_ADD, result); \ |
| 135 return *result; \ |
| 136 } |
| 137 |
| 138 #define SIMD4_SUB_FUNCTION(type) \ |
| 139 RUNTIME_FUNCTION(Runtime_##type##Sub) { \ |
| 140 HandleScope scope(isolate); \ |
| 141 SIMD4_BINARY_OP(type, a, b, BINARY_SUB, result); \ |
| 142 return *result; \ |
| 143 } |
| 144 |
| 145 #define SIMD4_MUL_FUNCTION(type) \ |
| 146 RUNTIME_FUNCTION(Runtime_##type##Mul) { \ |
| 147 HandleScope scope(isolate); \ |
| 148 SIMD4_BINARY_OP(type, a, b, BINARY_MUL, result); \ |
| 149 return *result; \ |
| 150 } |
| 151 |
| 152 #define SIMD4_DIV_FUNCTION(type) \ |
| 153 RUNTIME_FUNCTION(Runtime_##type##Div) { \ |
| 154 HandleScope scope(isolate); \ |
| 155 SIMD4_BINARY_OP(type, a, b, BINARY_DIV, result); \ |
| 156 return *result; \ |
| 157 } |
| 158 |
| 159 #define SIMD4_MIN_FUNCTION(type) \ |
| 160 RUNTIME_FUNCTION(Runtime_##type##Min) { \ |
| 161 HandleScope scope(isolate); \ |
| 162 SIMD4_BINARY_OP(type, a, b, Min, result); \ |
| 163 return *result; \ |
| 164 } |
| 165 |
| 166 #define SIMD4_MAX_FUNCTION(type) \ |
| 167 RUNTIME_FUNCTION(Runtime_##type##Max) { \ |
| 168 HandleScope scope(isolate); \ |
| 169 SIMD4_BINARY_OP(type, a, b, Max, result); \ |
| 170 return *result; \ |
| 171 } |
| 172 |
| 173 #define SIMD4_MINNUM_FUNCTION(type) \ |
| 174 RUNTIME_FUNCTION(Runtime_##type##MinNum) { \ |
| 175 HandleScope scope(isolate); \ |
| 176 SIMD4_BINARY_OP(type, a, b, MinNumber, result); \ |
| 177 return *result; \ |
| 178 } |
| 179 |
| 180 #define SIMD4_MAXNUM_FUNCTION(type) \ |
| 181 RUNTIME_FUNCTION(Runtime_##type##MaxNum) { \ |
| 182 HandleScope scope(isolate); \ |
| 183 SIMD4_BINARY_OP(type, a, b, MaxNumber, result); \ |
| 184 return *result; \ |
| 185 } |
| 186 |
| 187 #define SIMD4_SWIZZLE_FUNCTION(type) \ |
| 188 RUNTIME_FUNCTION(Runtime_##type##Swizzle) { \ |
| 189 HandleScope scope(isolate); \ |
| 190 DCHECK(args.length() == 5); \ |
| 191 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 192 CONVERT_SIMD_LANE_ARG_CHECKED(w, 1, 4); \ |
| 193 CONVERT_SIMD_LANE_ARG_CHECKED(x, 2, 4); \ |
| 194 CONVERT_SIMD_LANE_ARG_CHECKED(y, 3, 4); \ |
| 195 CONVERT_SIMD_LANE_ARG_CHECKED(z, 4, 4); \ |
| 196 Handle<type> result = isolate->factory()->New##type( \ |
| 197 a->get_lane(w), a->get_lane(x), a->get_lane(y), a->get_lane(z)); \ |
| 198 return *result; \ |
| 199 } |
| 200 |
| 201 #define SIMD4_SHUFFLE_FUNCTION(type) \ |
| 202 RUNTIME_FUNCTION(Runtime_##type##Shuffle) { \ |
| 203 HandleScope scope(isolate); \ |
| 204 DCHECK(args.length() == 6); \ |
| 205 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 206 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 207 CONVERT_SIMD_LANE_ARG_CHECKED(w, 2, 8); \ |
| 208 CONVERT_SIMD_LANE_ARG_CHECKED(x, 3, 8); \ |
| 209 CONVERT_SIMD_LANE_ARG_CHECKED(y, 4, 8); \ |
| 210 CONVERT_SIMD_LANE_ARG_CHECKED(z, 5, 8); \ |
| 211 float values[8]; \ |
| 212 values[0] = a->get_lane(0); \ |
| 213 values[1] = a->get_lane(1); \ |
| 214 values[2] = a->get_lane(2); \ |
| 215 values[3] = a->get_lane(3); \ |
| 216 values[4] = b->get_lane(0); \ |
| 217 values[5] = b->get_lane(1); \ |
| 218 values[6] = b->get_lane(2); \ |
| 219 values[7] = b->get_lane(3); \ |
| 220 Handle<type> result = isolate->factory()->New##type(values[w], values[x], \ |
| 221 values[y], values[z]); \ |
| 222 return *result; \ |
| 223 } |
| 224 |
| 225 #define SIMD4_FUNCTIONS(type) \ |
| 226 SIMD4_CREATE_FUNCTION(type) \ |
| 227 SIMD_CREATE_WRAPPER_FUNCTION(type) \ |
| 228 SIMD_CHECK_FUNCTION(type) \ |
| 229 SIMD4_EXTRACT_LANE_FUNCTION(type) \ |
| 230 SIMD4_REPLACE_LANE_FUNCTION(type) \ |
| 231 SIMD4_ABS_FUNCTION(type) \ |
| 232 SIMD4_NEG_FUNCTION(type) \ |
| 233 SIMD4_SQRT_FUNCTION(type) \ |
| 234 SIMD4_RECIP_APPROX_FUNCTION(type) \ |
| 235 SIMD4_RECIP_SQRT_APPROX_FUNCTION(type) \ |
| 236 SIMD4_ADD_FUNCTION(type) \ |
| 237 SIMD4_SUB_FUNCTION(type) \ |
| 238 SIMD4_MUL_FUNCTION(type) \ |
| 239 SIMD4_DIV_FUNCTION(type) \ |
| 240 SIMD4_MIN_FUNCTION(type) \ |
| 241 SIMD4_MAX_FUNCTION(type) \ |
| 242 SIMD4_MINNUM_FUNCTION(type) \ |
| 243 SIMD4_MAXNUM_FUNCTION(type) \ |
| 244 SIMD4_SWIZZLE_FUNCTION(type) \ |
| 245 SIMD4_SHUFFLE_FUNCTION(type) |
| 246 |
| 247 |
| 248 namespace v8 { |
| 249 namespace internal { |
| 250 |
| 251 namespace { |
| 252 |
| 253 // Convert from Number object to float. |
| 254 inline float NumberToFloat(Object* number) { |
| 255 // Don't bother checking for Smi, we might still overflow a float. |
| 256 return DoubleToFloat32(number->Number()); |
| 257 } |
| 258 |
| 259 |
| 260 inline float RecipApprox(float a) { return 1.0f / a; } |
| 261 |
| 262 |
| 263 inline float RecipSqrtApprox(float a) { return 1.0f / std::sqrt(a); } |
| 264 |
| 265 |
| 266 inline float Min(float a, float b) { |
| 267 if (a < b) return a; |
| 268 if (a > b) return b; |
| 269 if (a == b) return std::signbit(a) ? a : b; |
| 270 return std::numeric_limits<float>::quiet_NaN(); |
| 271 } |
| 272 |
| 273 |
| 274 inline float Max(float a, float b) { |
| 275 if (a > b) return a; |
| 276 if (a < b) return b; |
| 277 if (a == b) return std::signbit(b) ? a : b; |
| 278 return std::numeric_limits<float>::quiet_NaN(); |
| 279 } |
| 280 |
| 281 |
| 282 inline float MinNumber(float a, float b) { |
| 283 if (a != a) return b; |
| 284 if (b != b) return a; |
| 285 return Min(a, b); |
| 286 } |
| 287 |
| 288 |
| 289 inline float MaxNumber(float a, float b) { |
| 290 if (a != a) return b; |
| 291 if (b != b) return a; |
| 292 return Max(a, b); |
| 293 } |
| 294 } // namespace |
| 295 |
| 296 SIMD4_FUNCTIONS(Float32x4) |
| 297 } |
| 298 } // namespace v8::internal |
| OLD | NEW |