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)); \ | |
34 } | 30 } |
35 | 31 |
36 #define SIMD_CREATE_WRAPPER_FUNCTION(type) \ | 32 #define SIMD_CREATE_BOOLEAN_FUNCTION(type, lane_count) \ |
37 RUNTIME_FUNCTION(Runtime_New##type##Wrapper) { \ | 33 RUNTIME_FUNCTION(Runtime_Create##type) { \ |
38 HandleScope scope(isolate); \ | 34 HandleScope scope(isolate); \ |
39 DCHECK(args.length() == 1); \ | 35 DCHECK(args.length() == lane_count); \ |
40 CONVERT_ARG_HANDLE_CHECKED(type, value, 0); \ | 36 bool lanes[lane_count]; \ |
41 return *Object::ToObject(isolate, value).ToHandleChecked(); \ | 37 for (int i = 0; i < lane_count; i++) { \ |
38 lanes[i] = args[i]->BooleanValue(); \ | |
39 } \ | |
40 return *isolate->factory()->New##type(lanes); \ | |
42 } | 41 } |
43 | 42 |
44 #define SIMD_CHECK_FUNCTION(type) \ | 43 #define SIMD_CHECK_FUNCTION(type) \ |
45 RUNTIME_FUNCTION(Runtime_##type##Check) { \ | 44 RUNTIME_FUNCTION(Runtime_##type##Check) { \ |
46 HandleScope scope(isolate); \ | 45 HandleScope scope(isolate); \ |
47 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 46 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
48 return *a; \ | 47 return *a; \ |
49 } | 48 } |
50 | 49 |
51 #define SIMD_EXTRACT_LANE_FUNCTION(type, lanes) \ | 50 #define SIMD_EXTRACT_LANE_FUNCTION(type, lanes, extract_fn) \ |
52 RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ | 51 RUNTIME_FUNCTION(Runtime_##type##ExtractLane) { \ |
53 HandleScope scope(isolate); \ | 52 HandleScope scope(isolate); \ |
54 DCHECK(args.length() == 2); \ | 53 DCHECK(args.length() == 2); \ |
55 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 54 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ |
56 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ | 55 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lanes); \ |
57 return *isolate->factory()->NewNumber(a->get_lane(lane)); \ | 56 return *isolate->factory()->extract_fn(a->get_lane(lane)); \ |
58 } | 57 } |
59 | 58 |
60 #define SIMD4_EQUALS_FUNCTION(type) \ | 59 #define SIMD_REPLACE_NUMERIC_LANE_FUNCTION(type, lane_type, lane_count) \ |
61 RUNTIME_FUNCTION(Runtime_##type##Equals) { \ | 60 RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ |
62 HandleScope scope(isolate); \ | 61 HandleScope scope(isolate); \ |
63 DCHECK(args.length() == 2); \ | 62 DCHECK(args.length() == 3); \ |
64 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 63 CONVERT_ARG_HANDLE_CHECKED(type, simd, 0); \ |
65 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ | 64 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \ |
66 return Equals(a->get_lane(0), b->get_lane(0)) && \ | 65 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 2); \ |
67 Equals(a->get_lane(1), b->get_lane(1)) && \ | 66 lane_type lanes[lane_count]; \ |
68 Equals(a->get_lane(2), b->get_lane(2)) && \ | 67 for (int i = 0; i < lane_count; i++) { \ |
69 Equals(a->get_lane(3), b->get_lane(3)) \ | 68 lanes[i] = simd->get_lane(i); \ |
70 ? Smi::FromInt(EQUAL) \ | 69 } \ |
71 : Smi::FromInt(NOT_EQUAL); \ | 70 lanes[lane] = ConvertNumber<lane_type>(number->Number()); \ |
72 } | 71 Handle<type> result = isolate->factory()->New##type(lanes); \ |
73 | 72 return *result; \ |
74 #define SIMD4_SAME_VALUE_FUNCTION(type) \ | 73 } |
75 RUNTIME_FUNCTION(Runtime_##type##SameValue) { \ | 74 |
76 HandleScope scope(isolate); \ | 75 #define SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(type, lane_count) \ |
77 DCHECK(args.length() == 2); \ | 76 RUNTIME_FUNCTION(Runtime_##type##ReplaceLane) { \ |
78 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | 77 HandleScope scope(isolate); \ |
79 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ | 78 DCHECK(args.length() == 3); \ |
80 return isolate->heap()->ToBoolean( \ | 79 CONVERT_ARG_HANDLE_CHECKED(type, simd, 0); \ |
81 SameValue(a->get_lane(0), b->get_lane(0)) && \ | 80 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, lane_count); \ |
82 SameValue(a->get_lane(1), b->get_lane(1)) && \ | 81 bool lanes[lane_count]; \ |
83 SameValue(a->get_lane(2), b->get_lane(2)) && \ | 82 for (int i = 0; i < lane_count; i++) { \ |
84 SameValue(a->get_lane(3), b->get_lane(3))); \ | 83 lanes[i] = simd->get_lane(i); \ |
85 } | 84 } \ |
86 | 85 lanes[lane] = args[2]->BooleanValue(); \ |
87 #define SIMD4_SAME_VALUE_ZERO_FUNCTION(type) \ | 86 Handle<type> result = isolate->factory()->New##type(lanes); \ |
88 RUNTIME_FUNCTION(Runtime_##type##SameValueZero) { \ | 87 return *result; \ |
89 HandleScope scope(isolate); \ | 88 } |
90 DCHECK(args.length() == 2); \ | |
91 CONVERT_ARG_HANDLE_CHECKED(type, a, 0); \ | |
92 CONVERT_ARG_HANDLE_CHECKED(type, b, 1); \ | |
93 return isolate->heap()->ToBoolean( \ | |
94 SameValueZero(a->get_lane(0), b->get_lane(0)) && \ | |
95 SameValueZero(a->get_lane(1), b->get_lane(1)) && \ | |
96 SameValueZero(a->get_lane(2), b->get_lane(2)) && \ | |
97 SameValueZero(a->get_lane(3), b->get_lane(3))); \ | |
98 } | |
99 | |
100 #define SIMD4_EXTRACT_LANE_FUNCTION(type) SIMD_EXTRACT_LANE_FUNCTION(type, 4) | |
101 | |
102 #define SIMD4_FUNCTIONS(type) \ | |
103 SIMD4_CREATE_FUNCTION(type) \ | |
104 SIMD_CREATE_WRAPPER_FUNCTION(type) \ | |
105 SIMD_CHECK_FUNCTION(type) \ | |
106 SIMD4_EXTRACT_LANE_FUNCTION(type) \ | |
107 SIMD4_EQUALS_FUNCTION(type) \ | |
108 SIMD4_SAME_VALUE_FUNCTION(type) \ | |
109 SIMD4_SAME_VALUE_ZERO_FUNCTION(type) | |
110 | 89 |
111 | 90 |
112 namespace v8 { | 91 namespace v8 { |
113 namespace internal { | 92 namespace internal { |
114 | 93 |
115 namespace { | 94 namespace { |
116 | 95 |
117 // Convert from Number object to float. | 96 // Functions to convert Numbers to SIMD component types. |
118 inline float NumberToFloat(Object* number) { | 97 |
119 return DoubleToFloat32(number->Number()); | 98 template <typename T> |
120 } | 99 static T ConvertNumber(double number); |
121 | 100 |
122 | 101 |
123 inline bool Equals(float x, float y) { return x == y; } | 102 template <> |
103 float ConvertNumber<float>(double number) { | |
104 return DoubleToFloat32(number); | |
105 } | |
106 | |
107 | |
108 template <> | |
109 int32_t ConvertNumber<int32_t>(double number) { | |
110 return DoubleToInt32(number); | |
111 } | |
112 | |
113 | |
114 template <> | |
115 int16_t ConvertNumber<int16_t>(double number) { | |
116 return static_cast<int16_t>(DoubleToInt32(number)); | |
117 } | |
118 | |
119 | |
120 template <> | |
121 int8_t ConvertNumber<int8_t>(double number) { | |
122 return static_cast<int8_t>(DoubleToInt32(number)); | |
123 } | |
124 | |
125 | |
126 bool Equals(Float32x4* a, Float32x4* b) { | |
127 for (int i = 0; i < 4; i++) { | |
128 if (a->get_lane(i) != b->get_lane(i)) return false; | |
129 } | |
130 return true; | |
131 } | |
124 | 132 |
125 } // namespace | 133 } // namespace |
126 | 134 |
127 SIMD4_FUNCTIONS(Float32x4) | 135 |
136 RUNTIME_FUNCTION(Runtime_IsSimdValue) { | |
137 HandleScope scope(isolate); | |
138 DCHECK(args.length() == 1); | |
139 return isolate->heap()->ToBoolean(args[0]->IsSimd128Value()); | |
140 } | |
141 | |
142 | |
143 RUNTIME_FUNCTION(Runtime_SimdToObject) { | |
144 HandleScope scope(isolate); | |
145 DCHECK(args.length() == 1); | |
146 CONVERT_ARG_HANDLE_CHECKED(Simd128Value, value, 0); | |
147 return *Object::ToObject(isolate, value).ToHandleChecked(); | |
148 } | |
149 | |
150 | |
151 RUNTIME_FUNCTION(Runtime_SimdEquals) { | |
152 HandleScope scope(isolate); | |
153 DCHECK(args.length() == 2); | |
154 CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0); | |
155 bool result = false; | |
156 // args[1] is of unknown type. | |
157 if (args[1]->IsSimd128Value()) { | |
158 Simd128Value* b = Simd128Value::cast(args[1]); | |
159 if (a->map()->instance_type() == b->map()->instance_type()) { | |
160 if (a->IsFloat32x4()) { | |
161 result = Equals(Float32x4::cast(*a), Float32x4::cast(b)); | |
162 } else { | |
163 result = a->BitwiseEquals(b); | |
164 } | |
165 } | |
166 } | |
167 return Smi::FromInt(result ? EQUAL : NOT_EQUAL); | |
rossberg
2015/07/30 15:12:24
It is a bit strange to return an int here and Bool
bbudge
2015/07/30 23:27:01
It's driven by the call site, in EQUALS (runtime.j
| |
168 } | |
169 | |
170 | |
171 RUNTIME_FUNCTION(Runtime_SimdSameValue) { | |
172 HandleScope scope(isolate); | |
173 DCHECK(args.length() == 2); | |
174 CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0); | |
175 bool result = false; | |
176 // args[1] is of unknown type. | |
177 if (args[1]->IsSimd128Value()) { | |
178 Simd128Value* b = Simd128Value::cast(args[1]); | |
179 if (a->map()->instance_type() == b->map()->instance_type()) { | |
180 if (a->IsFloat32x4()) { | |
181 result = Float32x4::cast(*a)->SameValue(Float32x4::cast(b)); | |
182 } else { | |
183 result = a->BitwiseEquals(b); | |
184 } | |
185 } | |
186 } | |
187 return isolate->heap()->ToBoolean(result); | |
188 } | |
189 | |
190 | |
191 RUNTIME_FUNCTION(Runtime_SimdSameValueZero) { | |
192 HandleScope scope(isolate); | |
193 DCHECK(args.length() == 2); | |
194 CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0); | |
195 bool result = false; | |
196 // args[1] is of unknown type. | |
197 if (args[1]->IsSimd128Value()) { | |
198 Simd128Value* b = Simd128Value::cast(args[1]); | |
199 if (a->map()->instance_type() == b->map()->instance_type()) { | |
200 if (a->IsFloat32x4()) { | |
201 result = Float32x4::cast(*a)->SameValueZero(Float32x4::cast(b)); | |
202 } else { | |
203 result = a->BitwiseEquals(b); | |
204 } | |
205 } | |
206 } | |
207 return isolate->heap()->ToBoolean(result); | |
208 } | |
209 | |
210 | |
211 SIMD_CREATE_NUMERIC_FUNCTION(Float32x4, float, 4) | |
212 SIMD_CREATE_NUMERIC_FUNCTION(Int32x4, int32_t, 4) | |
213 SIMD_CREATE_BOOLEAN_FUNCTION(Bool32x4, 4) | |
214 SIMD_CREATE_NUMERIC_FUNCTION(Int16x8, int16_t, 8) | |
215 SIMD_CREATE_BOOLEAN_FUNCTION(Bool16x8, 8) | |
216 SIMD_CREATE_NUMERIC_FUNCTION(Int8x16, int8_t, 16) | |
217 SIMD_CREATE_BOOLEAN_FUNCTION(Bool8x16, 16) | |
218 | |
219 | |
220 SIMD_CHECK_FUNCTION(Float32x4) | |
221 SIMD_CHECK_FUNCTION(Int32x4) | |
222 SIMD_CHECK_FUNCTION(Bool32x4) | |
223 SIMD_CHECK_FUNCTION(Int16x8) | |
224 SIMD_CHECK_FUNCTION(Bool16x8) | |
225 SIMD_CHECK_FUNCTION(Int8x16) | |
226 SIMD_CHECK_FUNCTION(Bool8x16) | |
227 | |
228 | |
229 SIMD_EXTRACT_LANE_FUNCTION(Float32x4, 4, NewNumber) | |
230 SIMD_EXTRACT_LANE_FUNCTION(Int32x4, 4, NewNumber) | |
231 SIMD_EXTRACT_LANE_FUNCTION(Bool32x4, 4, ToBoolean) | |
232 SIMD_EXTRACT_LANE_FUNCTION(Int16x8, 8, NewNumber) | |
233 SIMD_EXTRACT_LANE_FUNCTION(Bool16x8, 8, ToBoolean) | |
234 SIMD_EXTRACT_LANE_FUNCTION(Int8x16, 16, NewNumber) | |
235 SIMD_EXTRACT_LANE_FUNCTION(Bool8x16, 16, ToBoolean) | |
236 | |
237 | |
238 RUNTIME_FUNCTION(Runtime_Int16x8UnsignedExtractLane) { | |
239 HandleScope scope(isolate); | |
240 DCHECK(args.length() == 2); | |
241 CONVERT_ARG_HANDLE_CHECKED(Int16x8, a, 0); | |
242 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 8); | |
243 return *isolate->factory()->NewNumber(bit_cast<uint16_t>(a->get_lane(lane))); | |
244 } | |
245 | |
246 | |
247 RUNTIME_FUNCTION(Runtime_Int8x16UnsignedExtractLane) { | |
248 HandleScope scope(isolate); | |
249 DCHECK(args.length() == 2); | |
250 CONVERT_ARG_HANDLE_CHECKED(Int8x16, a, 0); | |
251 CONVERT_SIMD_LANE_ARG_CHECKED(lane, 1, 16); | |
252 return *isolate->factory()->NewNumber(bit_cast<uint8_t>(a->get_lane(lane))); | |
253 } | |
254 | |
255 | |
256 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Float32x4, float, 4) | |
257 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int32x4, int32_t, 4) | |
258 SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool32x4, 4) | |
259 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int16x8, int16_t, 8) | |
260 SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool16x8, 8) | |
261 SIMD_REPLACE_NUMERIC_LANE_FUNCTION(Int8x16, int8_t, 16) | |
262 SIMD_REPLACE_BOOLEAN_LANE_FUNCTION(Bool8x16, 16) | |
128 } | 263 } |
129 } // namespace v8::internal | 264 } // namespace v8::internal |
OLD | NEW |