| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
| 8 #include "src/base/macros.h" | 8 #include "src/base/macros.h" |
| 9 #include "src/conversions.h" | 9 #include "src/conversions.h" |
| 10 #include "src/runtime/runtime-utils.h" | 10 #include "src/runtime/runtime-utils.h" |
| 11 | 11 |
| 12 // Implement Single Instruction Multiple Data (SIMD) operations as defined in | 12 // Implement Single Instruction Multiple Data (SIMD) operations as defined in |
| 13 // the SIMD.js draft spec: | 13 // the SIMD.js draft spec: |
| 14 // http://littledan.github.io/simd.html | 14 // http://littledan.github.io/simd.html |
| 15 | 15 |
| 16 #define NumberToFloat32x4Component NumberToFloat | |
| 17 | |
| 18 #define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \ | 16 #define CONVERT_SIMD_LANE_ARG_CHECKED(name, index, lanes) \ |
| 19 RUNTIME_ASSERT(args[index]->IsSmi()); \ | 17 CONVERT_INT32_ARG_CHECKED(name, index); \ |
| 20 int name = args.smi_at(index); \ | |
| 21 RUNTIME_ASSERT(name >= 0 && name < lanes); | 18 RUNTIME_ASSERT(name >= 0 && name < lanes); |
| 22 | 19 |
| 23 #define SIMD4_CREATE_FUNCTION(type) \ | 20 #define SIMD_CREATE_NUMERIC_FUNCTION(type, lane_type, lane_count) \ |
| 24 RUNTIME_FUNCTION(Runtime_Create##type) { \ | 21 RUNTIME_FUNCTION(Runtime_Create##type) { \ |
| 25 HandleScope scope(isolate); \ | 22 HandleScope scope(isolate); \ |
| 26 DCHECK(args.length() == 4); \ | 23 DCHECK(args.length() == lane_count); \ |
| 27 CONVERT_NUMBER_ARG_HANDLE_CHECKED(w, 0); \ | 24 lane_type lanes[lane_count]; \ |
| 28 CONVERT_NUMBER_ARG_HANDLE_CHECKED(x, 1); \ | 25 for (int i = 0; i < lane_count; i++) { \ |
| 29 CONVERT_NUMBER_ARG_HANDLE_CHECKED(y, 2); \ | 26 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, i); \ |
| 30 CONVERT_NUMBER_ARG_HANDLE_CHECKED(z, 3); \ | 27 lanes[i] = ConvertNumber<lane_type>(number->Number()); \ |
| 31 return *isolate->factory()->NewFloat32x4( \ | 28 } \ |
| 32 NumberTo##type##Component(*w), NumberTo##type##Component(*x), \ | 29 return *isolate->factory()->New##type(lanes); \ |
| 33 NumberTo##type##Component(*y), NumberTo##type##Component(*z)); \ | 30 } |
| 31 |
| 32 #define SIMD_CREATE_BOOLEAN_FUNCTION(type, lane_count) \ |
| 33 RUNTIME_FUNCTION(Runtime_Create##type) { \ |
| 34 HandleScope scope(isolate); \ |
| 35 DCHECK(args.length() == lane_count); \ |
| 36 bool lanes[lane_count]; \ |
| 37 for (int i = 0; i < lane_count; i++) { \ |
| 38 lanes[i] = args[i]->BooleanValue(); \ |
| 39 } \ |
| 40 return *isolate->factory()->New##type(lanes); \ |
| 34 } | 41 } |
| 35 | 42 |
| 36 #define SIMD_CREATE_WRAPPER_FUNCTION(type) \ | 43 #define SIMD_CREATE_WRAPPER_FUNCTION(type) \ |
| 37 RUNTIME_FUNCTION(Runtime_New##type##Wrapper) { \ | 44 RUNTIME_FUNCTION(Runtime_New##type##Wrapper) { \ |
| 38 HandleScope scope(isolate); \ | 45 HandleScope scope(isolate); \ |
| 39 DCHECK(args.length() == 1); \ | 46 DCHECK(args.length() == 1); \ |
| 40 CONVERT_ARG_HANDLE_CHECKED(type, value, 0); \ | 47 CONVERT_ARG_HANDLE_CHECKED(type, value, 0); \ |
| 41 return *Object::ToObject(isolate, value).ToHandleChecked(); \ | 48 return *Object::ToObject(isolate, value).ToHandleChecked(); \ |
| 42 } | 49 } |
| 43 | 50 |
| 44 #define SIMD_CHECK_FUNCTION(type) \ | 51 #define SIMD_CHECK_FUNCTION(type) \ |
| 45 RUNTIME_FUNCTION(Runtime_##type##Check) { \ | 52 RUNTIME_FUNCTION(Runtime_##type##Check) { \ |
| 46 HandleScope scope(isolate); \ | 53 HandleScope scope(isolate); \ |
| 47 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 54 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 48 return *a; \ | 55 return *a; \ |
| 49 } | 56 } |
| 50 | 57 |
| 51 #define SIMD_EXTRACT_LANE_FUNCTION(type, lanes) \ | 58 #define SIMD_EXTRACT_LANE_FUNCTION(type, lanes, extract_fn) \ |
| 52 RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ | 59 RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ |
| 53 HandleScope scope(isolate); \ | 60 HandleScope scope(isolate); \ |
| 54 DCHECK(args.length() == 2); \ | 61 DCHECK(args.length() == 2); \ |
| 55 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 62 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 56 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ | 63 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ |
| 57 return *isolate->factory()->NewNumber(a->get_lane(lane)); \ | 64 return *isolate->factory()->extract_fn(a->get_lane(lane)); \ |
| 58 } | 65 } |
| 59 | 66 |
| 60 #define SIMD4_EQUALS_FUNCTION(type) \ | 67 #define SIMD_REPLACE_NUMERIC_LANE_FUNCTION(type, lane_type, lane_count) \ |
| 61 RUNTIME_FUNCTION(Runtime_##type##Equals) { \ | 68 RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ |
| 62 HandleScope scope(isolate); \ | 69 HandleScope scope(isolate); \ |
| 63 DCHECK(args.length() == 2); \ | 70 DCHECK(args.length() == 3); \ |
| 64 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 71 CONVERT_ARG_HANDLE_CHECKED(type, simd, 0); \ |
| 65 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ | 72 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \ |
| 66 return Equals(a->get_lane(0), b->get_lane(0)) && \ | 73 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 2); \ |
| 67 Equals(a->get_lane(1), b->get_lane(1)) && \ | 74 lane_type lanes[lane_count]; \ |
| 68 Equals(a->get_lane(2), b->get_lane(2)) && \ | 75 for (int i = 0; i < lane_count; i++) { \ |
| 69 Equals(a->get_lane(3), b->get_lane(3)) \ | 76 lanes[i] = simd->get_lane(i); \ |
| 70 ? Smi::FromInt(EQUAL) \ | 77 } \ |
| 71 : Smi::FromInt(NOT_EQUAL); \ | 78 lanes[lane] = ConvertNumber<lane_type>(number->Number()); \ |
| 79 Handle<type> result = isolate->factory()->New##type(lanes); \ |
| 80 return *result; \ |
| 72 } | 81 } |
| 73 | 82 |
| 74 #define SIMD4_SAME_VALUE_FUNCTION(type) \ | 83 #define SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(type, lane_count) \ |
| 75 RUNTIME_FUNCTION(Runtime_##type##SameValue) { \ | 84 RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ |
| 76 HandleScope scope(isolate); \ | 85 HandleScope scope(isolate); \ |
| 77 DCHECK(args.length() == 2); \ | 86 DCHECK(args.length() == 3); \ |
| 78 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 87 CONVERT_ARG_HANDLE_CHECKED(type, simd, 0); \ |
| 79 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ | 88 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \ |
| 80 return isolate->heap()->ToBoolean( \ | 89 bool lanes[lane_count]; \ |
| 81 SameValue(a->get_lane(0), b->get_lane(0)) && \ | 90 for (int i = 0; i < lane_count; i++) { \ |
| 82 SameValue(a->get_lane(1), b->get_lane(1)) && \ | 91 lanes[i] = simd->get_lane(i); \ |
| 83 SameValue(a->get_lane(2), b->get_lane(2)) && \ | 92 } \ |
| 84 SameValue(a->get_lane(3), b->get_lane(3))); \ | 93 lanes[lane] = args[2]->BooleanValue(); \ |
| 94 Handle<type> result = isolate->factory()->New##type(lanes); \ |
| 95 return *result; \ |
| 85 } | 96 } |
| 86 | 97 |
| 87 #define SIMD4_SAME_VALUE_ZERO_FUNCTION(type) \ | 98 #define SIMD_EQUALS_FUNCTION(type, lanes) \ |
| 88 RUNTIME_FUNCTION(Runtime_##type##SameValueZero) { \ | 99 RUNTIME_FUNCTION(Runtime_##type##Equals) { \ |
| 89 HandleScope scope(isolate); \ | 100 HandleScope scope(isolate); \ |
| 90 DCHECK(args.length() == 2); \ | 101 DCHECK(args.length() == 2); \ |
| 91 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 102 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 92 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ | 103 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 93 return isolate->heap()->ToBoolean( \ | 104 for (int i = 0; i < lanes; i++) { \ |
| 94 SameValueZero(a->get_lane(0), b->get_lane(0)) && \ | 105 if (a->get_lane(i) != b->get_lane(i)) return Smi::FromInt(NOT_EQUAL); \ |
| 95 SameValueZero(a->get_lane(1), b->get_lane(1)) && \ | 106 } \ |
| 96 SameValueZero(a->get_lane(2), b->get_lane(2)) && \ | 107 return Smi::FromInt(EQUAL); \ |
| 97 SameValueZero(a->get_lane(3), b->get_lane(3))); \ | |
| 98 } | 108 } |
| 99 | 109 |
| 100 #define SIMD4_EXTRACT_LANE_FUNCTION(type) SIMD_EXTRACT_LANE_FUNCTION(type, 4) | 110 #define SIMD_SAME_VALUE_FLOAT_FUNCTION(type, lanes) \ |
| 111 RUNTIME_FUNCTION(Runtime_##type##SameValue) { \ |
| 112 HandleScope scope(isolate); \ |
| 113 DCHECK(args.length() == 2); \ |
| 114 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 115 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 116 bool same_value = a->SameValue(*b); \ |
| 117 return isolate->heap()->ToBoolean(same_value); \ |
| 118 } |
| 101 | 119 |
| 102 #define SIMD4_FUNCTIONS(type) \ | 120 #define SIMD_SAME_VALUE_ZERO_FLOAT_FUNCTION(type, lanes) \ |
| 103 SIMD4_CREATE_FUNCTION(type) \ | 121 RUNTIME_FUNCTION(Runtime_##type##SameValueZero) { \ |
| 104 SIMD_CREATE_WRAPPER_FUNCTION(type) \ | 122 HandleScope scope(isolate); \ |
| 105 SIMD_CHECK_FUNCTION(type) \ | 123 DCHECK(args.length() == 2); \ |
| 106 SIMD4_EXTRACT_LANE_FUNCTION(type) \ | 124 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 107 SIMD4_EQUALS_FUNCTION(type) \ | 125 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 108 SIMD4_SAME_VALUE_FUNCTION(type) \ | 126 bool same_value = a->SameValueZero(*b); \ |
| 109 SIMD4_SAME_VALUE_ZERO_FUNCTION(type) | 127 return isolate->heap()->ToBoolean(same_value); \ |
| 128 } |
| 129 |
| 130 #define SIMD_SAME_VALUE_FUNCTION(type, lanes) \ |
| 131 RUNTIME_FUNCTION(Runtime_##type##SameValue) { \ |
| 132 HandleScope scope(isolate); \ |
| 133 DCHECK(args.length() == 2); \ |
| 134 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 135 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 136 bool same_value = a->BitwiseEquals(*b); \ |
| 137 return isolate->heap()->ToBoolean(same_value); \ |
| 138 } |
| 139 |
| 140 #define SIMD_SAME_VALUE_ZERO_FUNCTION(type, lanes) \ |
| 141 RUNTIME_FUNCTION(Runtime_##type##SameValueZero) { \ |
| 142 HandleScope scope(isolate); \ |
| 143 DCHECK(args.length() == 2); \ |
| 144 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
| 145 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ |
| 146 bool same_value = a->BitwiseEquals(*b); \ |
| 147 return isolate->heap()->ToBoolean(same_value); \ |
| 148 } |
| 149 |
| 150 #define SIMD_FUNCTIONS(type, lanes, extract_fn) \ |
| 151 SIMD_CREATE_WRAPPER_FUNCTION(type) \ |
| 152 SIMD_CHECK_FUNCTION(type) \ |
| 153 SIMD_EXTRACT_LANE_FUNCTION(type, lanes, extract_fn) \ |
| 154 SIMD_EQUALS_FUNCTION(type, lanes) |
| 110 | 155 |
| 111 | 156 |
| 112 namespace v8 { | 157 namespace v8 { |
| 113 namespace internal { | 158 namespace internal { |
| 114 | 159 |
| 115 namespace { | 160 namespace { |
| 116 | 161 |
| 117 // Convert from Number object to float. | 162 // Functions to convert Numbers to SIMD component types. |
| 118 inline float NumberToFloat(Object* number) { | 163 |
| 119 return DoubleToFloat32(number->Number()); | 164 template <typename T> |
| 165 static T ConvertNumber(double number); |
| 166 |
| 167 |
| 168 template <> |
| 169 float ConvertNumber<float>(double number) { |
| 170 return DoubleToFloat32(number); |
| 120 } | 171 } |
| 121 | 172 |
| 122 | 173 |
| 123 inline bool Equals(float x, float y) { return x == y; } | 174 template <> |
| 175 int32_t ConvertNumber<int32_t>(double number) { |
| 176 return DoubleToInt32(number); |
| 177 } |
| 178 |
| 179 |
| 180 template <> |
| 181 int16_t ConvertNumber<int16_t>(double number) { |
| 182 return static_cast<int16_t>(DoubleToInt32(number)); |
| 183 } |
| 184 |
| 185 |
| 186 template <> |
| 187 int8_t ConvertNumber<int8_t>(double number) { |
| 188 return static_cast<int8_t>(DoubleToInt32(number)); |
| 189 } |
| 124 | 190 |
| 125 } // namespace | 191 } // namespace |
| 126 | 192 |
| 127 SIMD4_FUNCTIONS(Float32x4) | 193 |
| 194 SIMD_CREATE_NUMERIC_FUNCTION(Float32x4, float, 4) |
| 195 SIMD_CREATE_NUMERIC_FUNCTION(Int32x4, int32_t, 4) |
| 196 SIMD_CREATE_BOOLEAN_FUNCTION(Bool32x4, 4) |
| 197 SIMD_CREATE_NUMERIC_FUNCTION(Int16x8, int16_t, 8) |
| 198 SIMD_CREATE_BOOLEAN_FUNCTION(Bool16x8, 8) |
| 199 SIMD_CREATE_NUMERIC_FUNCTION(Int8x16, int8_t, 16) |
| 200 SIMD_CREATE_BOOLEAN_FUNCTION(Bool8x16, 16) |
| 201 |
| 202 |
| 203 RUNTIME_FUNCTION(Runtime_Int16x8UnsignedExtractLane) { |
| 204 HandleScope scope(isolate); |
| 205 DCHECK(args.length() == 2); |
| 206 CONVERT_ARG_HANDLE_CHECKED(Int16x8, a, 0); |
| 207 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 8); |
| 208 return *isolate->factory()->NewNumber(bit_cast<uint16_t>(a->get_lane(lane))); |
| 209 } |
| 210 |
| 211 |
| 212 RUNTIME_FUNCTION(Runtime_Int8x16UnsignedExtractLane) { |
| 213 HandleScope scope(isolate); |
| 214 DCHECK(args.length() == 2); |
| 215 CONVERT_ARG_HANDLE_CHECKED(Int8x16, a, 0); |
| 216 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 16); |
| 217 return *isolate->factory()->NewNumber(bit_cast<uint8_t>(a->get_lane(lane))); |
| 218 } |
| 219 |
| 220 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Float32x4, float, 4) |
| 221 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int32x4, int32_t, 4) |
| 222 SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool32x4, 4) |
| 223 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int16x8, int16_t, 8) |
| 224 SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool16x8, 8) |
| 225 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int8x16, int8_t, 16) |
| 226 SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool8x16, 16) |
| 227 |
| 228 |
| 229 SIMD_SAME_VALUE_FLOAT_FUNCTION(Float32x4, 4) |
| 230 SIMD_SAME_VALUE_FUNCTION(Int32x4, 4) |
| 231 SIMD_SAME_VALUE_FUNCTION(Bool32x4, 4) |
| 232 SIMD_SAME_VALUE_FUNCTION(Int16x8, 8) |
| 233 SIMD_SAME_VALUE_FUNCTION(Bool16x8, 8) |
| 234 SIMD_SAME_VALUE_FUNCTION(Int8x16, 16) |
| 235 SIMD_SAME_VALUE_FUNCTION(Bool8x16, 16) |
| 236 |
| 237 |
| 238 SIMD_SAME_VALUE_ZERO_FLOAT_FUNCTION(Float32x4, 4) |
| 239 SIMD_SAME_VALUE_ZERO_FUNCTION(Int32x4, 4) |
| 240 SIMD_SAME_VALUE_ZERO_FUNCTION(Bool32x4, 4) |
| 241 SIMD_SAME_VALUE_ZERO_FUNCTION(Int16x8, 8) |
| 242 SIMD_SAME_VALUE_ZERO_FUNCTION(Bool16x8, 8) |
| 243 SIMD_SAME_VALUE_ZERO_FUNCTION(Int8x16, 16) |
| 244 SIMD_SAME_VALUE_ZERO_FUNCTION(Bool8x16, 16) |
| 245 |
| 246 |
| 247 SIMD_FUNCTIONS(Float32x4, 4, NewNumber) |
| 248 SIMD_FUNCTIONS(Int32x4, 4, NewNumber) |
| 249 SIMD_FUNCTIONS(Bool32x4, 4, ToBoolean) |
| 250 SIMD_FUNCTIONS(Int16x8, 8, NewNumber) |
| 251 SIMD_FUNCTIONS(Bool16x8, 8, ToBoolean) |
| 252 SIMD_FUNCTIONS(Int8x16, 16, NewNumber) |
| 253 SIMD_FUNCTIONS(Bool8x16, 16, ToBoolean) |
| 128 } | 254 } |
| 129 } // namespace v8::internal | 255 } // namespace v8::internal |
| OLD | NEW |