1/*
2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "AirCode.h"
29#include "AirGenerate.h"
30#include "AirInstInlines.h"
31#include "AirSpecial.h"
32#include "AllowMacroScratchRegisterUsage.h"
33#include "B3BasicBlockInlines.h"
34#include "B3Compilation.h"
35#include "B3Procedure.h"
36#include "B3PatchpointSpecial.h"
37#include "CCallHelpers.h"
38#include "InitializeThreading.h"
39#include "JSCInlines.h"
40#include "LinkBuffer.h"
41#include "ProbeContext.h"
42#include "PureNaN.h"
43#include <cmath>
44#include <regex>
45#include <string>
46#include <wtf/Lock.h>
47#include <wtf/NumberOfCores.h>
48#include <wtf/StdMap.h>
49#include <wtf/Threading.h>
50#include <wtf/text/StringCommon.h>
51
52// We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
53static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
54
55static void usage()
56{
57 dataLog("Usage: testair [<filter>]\n");
58 if (hiddenTruthBecauseNoReturnIsStupid())
59 exit(1);
60}
61
62#if ENABLE(B3_JIT)
63
64using namespace JSC;
65using namespace JSC::B3::Air;
66
67using JSC::B3::FP;
68using JSC::B3::GP;
69using JSC::B3::Width;
70using JSC::B3::Width8;
71using JSC::B3::Width16;
72using JSC::B3::Width32;
73using JSC::B3::Width64;
74
75namespace {
76
77Lock crashLock;
78
79// Nothing fancy for now; we just use the existing WTF assertion machinery.
80#define CHECK(x) do { \
81 if (!!(x)) \
82 break; \
83 crashLock.lock(); \
84 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
85 CRASH(); \
86 } while (false)
87
88std::unique_ptr<B3::Compilation> compile(B3::Procedure& proc)
89{
90 prepareForGeneration(proc.code());
91 CCallHelpers jit;
92 generate(proc.code(), jit);
93 LinkBuffer linkBuffer(jit, nullptr);
94
95 return makeUnique<B3::Compilation>(
96 FINALIZE_CODE(linkBuffer, B3CompilationPtrTag, "testair compilation"), proc.releaseByproducts());
97}
98
99template<typename T, typename... Arguments>
100T invoke(const B3::Compilation& code, Arguments... arguments)
101{
102 void* executableAddress = untagCFunctionPtr(code.code().executableAddress(), B3CompilationPtrTag);
103 T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(executableAddress);
104 return function(arguments...);
105}
106
107template<typename T, typename... Arguments>
108T compileAndRun(B3::Procedure& procedure, Arguments... arguments)
109{
110 return invoke<T>(*compile(procedure), arguments...);
111}
112
113void testSimple()
114{
115 B3::Procedure proc;
116 Code& code = proc.code();
117
118 BasicBlock* root = code.addBlock();
119 root->append(Move, nullptr, Arg::imm(42), Tmp(GPRInfo::returnValueGPR));
120 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
121
122 CHECK(compileAndRun<int>(proc) == 42);
123}
124
125// Use this to put a constant into a register without Air being able to see the constant.
126template<typename T>
127void loadConstantImpl(BasicBlock* block, T value, B3::Air::Opcode move, Tmp tmp, Tmp scratch)
128{
129 static Lock lock;
130 static StdMap<T, T*>* map; // I'm not messing with HashMap's problems with integers.
131
132 LockHolder locker(lock);
133 if (!map)
134 map = new StdMap<T, T*>();
135
136 if (!map->count(value))
137 (*map)[value] = new T(value);
138
139 T* ptr = (*map)[value];
140 block->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(ptr)), scratch);
141 block->append(move, nullptr, Arg::addr(scratch), tmp);
142}
143
144template<typename T>
145void loadConstant(BasicBlock* block, T value, Tmp tmp)
146{
147 loadConstantImpl(block, value, Move, tmp, tmp);
148}
149
150void loadDoubleConstant(BasicBlock* block, double value, Tmp tmp, Tmp scratch)
151{
152 loadConstantImpl<double>(block, value, MoveDouble, tmp, scratch);
153}
154
155void testShuffleSimpleSwap()
156{
157 B3::Procedure proc;
158 Code& code = proc.code();
159
160 BasicBlock* root = code.addBlock();
161 loadConstant(root, 1, Tmp(GPRInfo::regT0));
162 loadConstant(root, 2, Tmp(GPRInfo::regT1));
163 loadConstant(root, 3, Tmp(GPRInfo::regT2));
164 loadConstant(root, 4, Tmp(GPRInfo::regT3));
165 root->append(
166 Shuffle, nullptr,
167 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
168 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT2), Arg::widthArg(Width32));
169
170 int32_t things[4];
171 Tmp base = code.newTmp(GP);
172 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
173 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
174 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
175 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
176 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
177 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
178 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
179
180 memset(things, 0, sizeof(things));
181
182 CHECK(!compileAndRun<int>(proc));
183
184 CHECK(things[0] == 1);
185 CHECK(things[1] == 2);
186 CHECK(things[2] == 4);
187 CHECK(things[3] == 3);
188}
189
190void testShuffleSimpleShift()
191{
192 B3::Procedure proc;
193 Code& code = proc.code();
194
195 BasicBlock* root = code.addBlock();
196 loadConstant(root, 1, Tmp(GPRInfo::regT0));
197 loadConstant(root, 2, Tmp(GPRInfo::regT1));
198 loadConstant(root, 3, Tmp(GPRInfo::regT2));
199 loadConstant(root, 4, Tmp(GPRInfo::regT3));
200 root->append(
201 Shuffle, nullptr,
202 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
203 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32));
204
205 int32_t things[5];
206 Tmp base = code.newTmp(GP);
207 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
208 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
209 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
210 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
211 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
212 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
213 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
214 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
215
216 memset(things, 0, sizeof(things));
217
218 CHECK(!compileAndRun<int>(proc));
219
220 CHECK(things[0] == 1);
221 CHECK(things[1] == 2);
222 CHECK(things[2] == 3);
223 CHECK(things[3] == 3);
224 CHECK(things[4] == 4);
225}
226
227void testShuffleLongShift()
228{
229 B3::Procedure proc;
230 Code& code = proc.code();
231
232 BasicBlock* root = code.addBlock();
233 loadConstant(root, 1, Tmp(GPRInfo::regT0));
234 loadConstant(root, 2, Tmp(GPRInfo::regT1));
235 loadConstant(root, 3, Tmp(GPRInfo::regT2));
236 loadConstant(root, 4, Tmp(GPRInfo::regT3));
237 loadConstant(root, 5, Tmp(GPRInfo::regT4));
238 loadConstant(root, 6, Tmp(GPRInfo::regT5));
239 loadConstant(root, 7, Tmp(GPRInfo::regT6));
240 loadConstant(root, 8, Tmp(GPRInfo::regT7));
241 root->append(
242 Shuffle, nullptr,
243 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
244 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
245 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
246 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
247 Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
248 Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT6), Arg::widthArg(Width32),
249 Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT7), Arg::widthArg(Width32));
250
251 int32_t things[8];
252 Tmp base = code.newTmp(GP);
253 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
254 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
255 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
256 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
257 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
258 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
259 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
260 root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
261 root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
262 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
263 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
264
265 memset(things, 0, sizeof(things));
266
267 CHECK(!compileAndRun<int>(proc));
268
269 CHECK(things[0] == 1);
270 CHECK(things[1] == 1);
271 CHECK(things[2] == 2);
272 CHECK(things[3] == 3);
273 CHECK(things[4] == 4);
274 CHECK(things[5] == 5);
275 CHECK(things[6] == 6);
276 CHECK(things[7] == 7);
277}
278
279void testShuffleLongShiftBackwards()
280{
281 B3::Procedure proc;
282 Code& code = proc.code();
283
284 BasicBlock* root = code.addBlock();
285 loadConstant(root, 1, Tmp(GPRInfo::regT0));
286 loadConstant(root, 2, Tmp(GPRInfo::regT1));
287 loadConstant(root, 3, Tmp(GPRInfo::regT2));
288 loadConstant(root, 4, Tmp(GPRInfo::regT3));
289 loadConstant(root, 5, Tmp(GPRInfo::regT4));
290 loadConstant(root, 6, Tmp(GPRInfo::regT5));
291 loadConstant(root, 7, Tmp(GPRInfo::regT6));
292 loadConstant(root, 8, Tmp(GPRInfo::regT7));
293 root->append(
294 Shuffle, nullptr,
295 Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT7), Arg::widthArg(Width32),
296 Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT6), Arg::widthArg(Width32),
297 Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
298 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
299 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
300 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
301 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32));
302
303 int32_t things[8];
304 Tmp base = code.newTmp(GP);
305 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
306 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
307 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
308 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
309 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
310 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
311 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
312 root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
313 root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
314 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
315 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
316
317 memset(things, 0, sizeof(things));
318
319 CHECK(!compileAndRun<int>(proc));
320
321 CHECK(things[0] == 1);
322 CHECK(things[1] == 1);
323 CHECK(things[2] == 2);
324 CHECK(things[3] == 3);
325 CHECK(things[4] == 4);
326 CHECK(things[5] == 5);
327 CHECK(things[6] == 6);
328 CHECK(things[7] == 7);
329}
330
331void testShuffleSimpleRotate()
332{
333 B3::Procedure proc;
334 Code& code = proc.code();
335
336 BasicBlock* root = code.addBlock();
337 loadConstant(root, 1, Tmp(GPRInfo::regT0));
338 loadConstant(root, 2, Tmp(GPRInfo::regT1));
339 loadConstant(root, 3, Tmp(GPRInfo::regT2));
340 loadConstant(root, 4, Tmp(GPRInfo::regT3));
341 root->append(
342 Shuffle, nullptr,
343 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
344 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
345 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Width32));
346
347 int32_t things[4];
348 Tmp base = code.newTmp(GP);
349 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
350 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
351 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
352 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
353 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
354 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
355 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
356
357 memset(things, 0, sizeof(things));
358
359 CHECK(!compileAndRun<int>(proc));
360
361 CHECK(things[0] == 3);
362 CHECK(things[1] == 1);
363 CHECK(things[2] == 2);
364 CHECK(things[3] == 4);
365}
366
367void testShuffleSimpleBroadcast()
368{
369 B3::Procedure proc;
370 Code& code = proc.code();
371
372 BasicBlock* root = code.addBlock();
373 loadConstant(root, 1, Tmp(GPRInfo::regT0));
374 loadConstant(root, 2, Tmp(GPRInfo::regT1));
375 loadConstant(root, 3, Tmp(GPRInfo::regT2));
376 loadConstant(root, 4, Tmp(GPRInfo::regT3));
377 root->append(
378 Shuffle, nullptr,
379 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
380 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
381 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Width32));
382
383 int32_t things[4];
384 Tmp base = code.newTmp(GP);
385 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
386 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
387 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
388 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
389 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
390 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
391 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
392
393 memset(things, 0, sizeof(things));
394
395 CHECK(!compileAndRun<int>(proc));
396
397 CHECK(things[0] == 1);
398 CHECK(things[1] == 1);
399 CHECK(things[2] == 1);
400 CHECK(things[3] == 1);
401}
402
403void testShuffleBroadcastAllRegs()
404{
405 B3::Procedure proc;
406 Code& code = proc.code();
407
408 const Vector<Reg>& regs = code.regsInPriorityOrder(GP);
409
410 BasicBlock* root = code.addBlock();
411 root->append(Move, nullptr, Arg::imm(35), Tmp(GPRInfo::regT0));
412 unsigned count = 1;
413 for (Reg reg : regs) {
414 if (reg != Reg(GPRInfo::regT0))
415 loadConstant(root, count++, Tmp(reg));
416 }
417 Inst& shuffle = root->append(Shuffle, nullptr);
418 for (Reg reg : regs) {
419 if (reg != Reg(GPRInfo::regT0))
420 shuffle.append(Tmp(GPRInfo::regT0), Tmp(reg), Arg::widthArg(Width32));
421 }
422
423 StackSlot* slot = code.addStackSlot(sizeof(int32_t) * regs.size(), StackSlotKind::Locked);
424 for (unsigned i = 0; i < regs.size(); ++i)
425 root->append(Move32, nullptr, Tmp(regs[i]), Arg::stack(slot, i * sizeof(int32_t)));
426
427 Vector<int32_t> things(regs.size(), 666);
428 Tmp base = code.newTmp(GP);
429 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), base);
430 for (unsigned i = 0; i < regs.size(); ++i) {
431 root->append(Move32, nullptr, Arg::stack(slot, i * sizeof(int32_t)), Tmp(GPRInfo::regT0));
432 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, i * sizeof(int32_t)));
433 }
434
435 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
436 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
437
438 CHECK(!compileAndRun<int>(proc));
439
440 for (int32_t thing : things)
441 CHECK(thing == 35);
442}
443
444void testShuffleTreeShift()
445{
446 B3::Procedure proc;
447 Code& code = proc.code();
448
449 BasicBlock* root = code.addBlock();
450 loadConstant(root, 1, Tmp(GPRInfo::regT0));
451 loadConstant(root, 2, Tmp(GPRInfo::regT1));
452 loadConstant(root, 3, Tmp(GPRInfo::regT2));
453 loadConstant(root, 4, Tmp(GPRInfo::regT3));
454 loadConstant(root, 5, Tmp(GPRInfo::regT4));
455 loadConstant(root, 6, Tmp(GPRInfo::regT5));
456 loadConstant(root, 7, Tmp(GPRInfo::regT6));
457 loadConstant(root, 8, Tmp(GPRInfo::regT7));
458 root->append(
459 Shuffle, nullptr,
460 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
461 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
462 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
463 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
464 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
465 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT6), Arg::widthArg(Width32),
466 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT7), Arg::widthArg(Width32));
467
468 int32_t things[8];
469 Tmp base = code.newTmp(GP);
470 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
471 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
472 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
473 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
474 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
475 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
476 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
477 root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
478 root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
479 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
480 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
481
482 memset(things, 0, sizeof(things));
483
484 CHECK(!compileAndRun<int>(proc));
485
486 CHECK(things[0] == 1);
487 CHECK(things[1] == 1);
488 CHECK(things[2] == 1);
489 CHECK(things[3] == 2);
490 CHECK(things[4] == 2);
491 CHECK(things[5] == 3);
492 CHECK(things[6] == 3);
493 CHECK(things[7] == 4);
494}
495
496void testShuffleTreeShiftBackward()
497{
498 B3::Procedure proc;
499 Code& code = proc.code();
500
501 BasicBlock* root = code.addBlock();
502 loadConstant(root, 1, Tmp(GPRInfo::regT0));
503 loadConstant(root, 2, Tmp(GPRInfo::regT1));
504 loadConstant(root, 3, Tmp(GPRInfo::regT2));
505 loadConstant(root, 4, Tmp(GPRInfo::regT3));
506 loadConstant(root, 5, Tmp(GPRInfo::regT4));
507 loadConstant(root, 6, Tmp(GPRInfo::regT5));
508 loadConstant(root, 7, Tmp(GPRInfo::regT6));
509 loadConstant(root, 8, Tmp(GPRInfo::regT7));
510 root->append(
511 Shuffle, nullptr,
512 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT7), Arg::widthArg(Width32),
513 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT6), Arg::widthArg(Width32),
514 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
515 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
516 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
517 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
518 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32));
519
520 int32_t things[8];
521 Tmp base = code.newTmp(GP);
522 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
523 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
524 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
525 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
526 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
527 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
528 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
529 root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
530 root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
531 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
532 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
533
534 memset(things, 0, sizeof(things));
535
536 CHECK(!compileAndRun<int>(proc));
537
538 CHECK(things[0] == 1);
539 CHECK(things[1] == 1);
540 CHECK(things[2] == 1);
541 CHECK(things[3] == 2);
542 CHECK(things[4] == 2);
543 CHECK(things[5] == 3);
544 CHECK(things[6] == 3);
545 CHECK(things[7] == 4);
546}
547
548void testShuffleTreeShiftOtherBackward()
549{
550 // NOTE: This test was my original attempt at TreeShiftBackward but mistakes were made. So, this
551 // ends up being just a weird test. But weird tests are useful, so I kept it.
552
553 B3::Procedure proc;
554 Code& code = proc.code();
555
556 BasicBlock* root = code.addBlock();
557 loadConstant(root, 1, Tmp(GPRInfo::regT0));
558 loadConstant(root, 2, Tmp(GPRInfo::regT1));
559 loadConstant(root, 3, Tmp(GPRInfo::regT2));
560 loadConstant(root, 4, Tmp(GPRInfo::regT3));
561 loadConstant(root, 5, Tmp(GPRInfo::regT4));
562 loadConstant(root, 6, Tmp(GPRInfo::regT5));
563 loadConstant(root, 7, Tmp(GPRInfo::regT6));
564 loadConstant(root, 8, Tmp(GPRInfo::regT7));
565 root->append(
566 Shuffle, nullptr,
567 Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT7), Arg::widthArg(Width32),
568 Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT6), Arg::widthArg(Width32),
569 Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
570 Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
571 Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
572 Tmp(GPRInfo::regT7), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
573 Tmp(GPRInfo::regT7), Tmp(GPRInfo::regT1), Arg::widthArg(Width32));
574
575 int32_t things[8];
576 Tmp base = code.newTmp(GP);
577 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
578 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
579 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
580 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
581 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
582 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
583 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
584 root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
585 root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
586 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
587 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
588
589 memset(things, 0, sizeof(things));
590
591 CHECK(!compileAndRun<int>(proc));
592
593 CHECK(things[0] == 1);
594 CHECK(things[1] == 8);
595 CHECK(things[2] == 8);
596 CHECK(things[3] == 7);
597 CHECK(things[4] == 7);
598 CHECK(things[5] == 6);
599 CHECK(things[6] == 6);
600 CHECK(things[7] == 5);
601}
602
603void testShuffleMultipleShifts()
604{
605 B3::Procedure proc;
606 Code& code = proc.code();
607
608 BasicBlock* root = code.addBlock();
609 loadConstant(root, 1, Tmp(GPRInfo::regT0));
610 loadConstant(root, 2, Tmp(GPRInfo::regT1));
611 loadConstant(root, 3, Tmp(GPRInfo::regT2));
612 loadConstant(root, 4, Tmp(GPRInfo::regT3));
613 loadConstant(root, 5, Tmp(GPRInfo::regT4));
614 loadConstant(root, 6, Tmp(GPRInfo::regT5));
615 root->append(
616 Shuffle, nullptr,
617 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
618 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
619 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
620 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT5), Arg::widthArg(Width32));
621
622 int32_t things[6];
623 Tmp base = code.newTmp(GP);
624 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
625 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
626 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
627 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
628 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
629 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
630 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
631 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
632 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
633
634 memset(things, 0, sizeof(things));
635
636 CHECK(!compileAndRun<int>(proc));
637
638 CHECK(things[0] == 1);
639 CHECK(things[1] == 1);
640 CHECK(things[2] == 3);
641 CHECK(things[3] == 3);
642 CHECK(things[4] == 3);
643 CHECK(things[5] == 1);
644}
645
646void testShuffleRotateWithFringe()
647{
648 B3::Procedure proc;
649 Code& code = proc.code();
650
651 BasicBlock* root = code.addBlock();
652 loadConstant(root, 1, Tmp(GPRInfo::regT0));
653 loadConstant(root, 2, Tmp(GPRInfo::regT1));
654 loadConstant(root, 3, Tmp(GPRInfo::regT2));
655 loadConstant(root, 4, Tmp(GPRInfo::regT3));
656 loadConstant(root, 5, Tmp(GPRInfo::regT4));
657 loadConstant(root, 6, Tmp(GPRInfo::regT5));
658 root->append(
659 Shuffle, nullptr,
660 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
661 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
662 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Width32),
663 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
664 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
665 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Width32));
666
667 int32_t things[6];
668 Tmp base = code.newTmp(GP);
669 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
670 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
671 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
672 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
673 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
674 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
675 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
676 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
677 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
678
679 memset(things, 0, sizeof(things));
680
681 CHECK(!compileAndRun<int>(proc));
682
683 CHECK(things[0] == 3);
684 CHECK(things[1] == 1);
685 CHECK(things[2] == 2);
686 CHECK(things[3] == 1);
687 CHECK(things[4] == 2);
688 CHECK(things[5] == 3);
689}
690
691void testShuffleRotateWithFringeInWeirdOrder()
692{
693 B3::Procedure proc;
694 Code& code = proc.code();
695
696 BasicBlock* root = code.addBlock();
697 loadConstant(root, 1, Tmp(GPRInfo::regT0));
698 loadConstant(root, 2, Tmp(GPRInfo::regT1));
699 loadConstant(root, 3, Tmp(GPRInfo::regT2));
700 loadConstant(root, 4, Tmp(GPRInfo::regT3));
701 loadConstant(root, 5, Tmp(GPRInfo::regT4));
702 loadConstant(root, 6, Tmp(GPRInfo::regT5));
703 root->append(
704 Shuffle, nullptr,
705 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
706 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
707 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
708 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Width32),
709 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
710 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32));
711
712 int32_t things[6];
713 Tmp base = code.newTmp(GP);
714 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
715 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
716 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
717 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
718 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
719 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
720 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
721 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
722 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
723
724 memset(things, 0, sizeof(things));
725
726 CHECK(!compileAndRun<int>(proc));
727
728 CHECK(things[0] == 3);
729 CHECK(things[1] == 1);
730 CHECK(things[2] == 2);
731 CHECK(things[3] == 1);
732 CHECK(things[4] == 2);
733 CHECK(things[5] == 3);
734}
735
736void testShuffleRotateWithLongFringe()
737{
738 B3::Procedure proc;
739 Code& code = proc.code();
740
741 BasicBlock* root = code.addBlock();
742 loadConstant(root, 1, Tmp(GPRInfo::regT0));
743 loadConstant(root, 2, Tmp(GPRInfo::regT1));
744 loadConstant(root, 3, Tmp(GPRInfo::regT2));
745 loadConstant(root, 4, Tmp(GPRInfo::regT3));
746 loadConstant(root, 5, Tmp(GPRInfo::regT4));
747 loadConstant(root, 6, Tmp(GPRInfo::regT5));
748 root->append(
749 Shuffle, nullptr,
750 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
751 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
752 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Width32),
753 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
754 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
755 Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Width32));
756
757 int32_t things[6];
758 Tmp base = code.newTmp(GP);
759 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
760 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
761 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
762 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
763 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
764 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
765 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
766 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
767 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
768
769 memset(things, 0, sizeof(things));
770
771 CHECK(!compileAndRun<int>(proc));
772
773 CHECK(things[0] == 3);
774 CHECK(things[1] == 1);
775 CHECK(things[2] == 2);
776 CHECK(things[3] == 1);
777 CHECK(things[4] == 4);
778 CHECK(things[5] == 5);
779}
780
781void testShuffleMultipleRotates()
782{
783 B3::Procedure proc;
784 Code& code = proc.code();
785
786 BasicBlock* root = code.addBlock();
787 loadConstant(root, 1, Tmp(GPRInfo::regT0));
788 loadConstant(root, 2, Tmp(GPRInfo::regT1));
789 loadConstant(root, 3, Tmp(GPRInfo::regT2));
790 loadConstant(root, 4, Tmp(GPRInfo::regT3));
791 loadConstant(root, 5, Tmp(GPRInfo::regT4));
792 loadConstant(root, 6, Tmp(GPRInfo::regT5));
793 root->append(
794 Shuffle, nullptr,
795 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
796 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
797 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Width32),
798 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
799 Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Width32),
800 Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT3), Arg::widthArg(Width32));
801
802 int32_t things[6];
803 Tmp base = code.newTmp(GP);
804 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
805 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
806 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
807 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
808 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
809 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
810 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
811 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
812 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
813
814 memset(things, 0, sizeof(things));
815
816 CHECK(!compileAndRun<int>(proc));
817
818 CHECK(things[0] == 3);
819 CHECK(things[1] == 1);
820 CHECK(things[2] == 2);
821 CHECK(things[3] == 6);
822 CHECK(things[4] == 4);
823 CHECK(things[5] == 5);
824}
825
826void testShuffleShiftAndRotate()
827{
828 B3::Procedure proc;
829 Code& code = proc.code();
830
831 BasicBlock* root = code.addBlock();
832 loadConstant(root, 1, Tmp(GPRInfo::regT0));
833 loadConstant(root, 2, Tmp(GPRInfo::regT1));
834 loadConstant(root, 3, Tmp(GPRInfo::regT2));
835 loadConstant(root, 4, Tmp(GPRInfo::regT3));
836 loadConstant(root, 5, Tmp(GPRInfo::regT4));
837 loadConstant(root, 6, Tmp(GPRInfo::regT5));
838 root->append(
839 Shuffle, nullptr,
840 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
841 Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Width32),
842 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Width32),
843 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32),
844 Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Width32));
845
846 int32_t things[6];
847 Tmp base = code.newTmp(GP);
848 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
849 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
850 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
851 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
852 root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
853 root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
854 root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
855 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
856 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
857
858 memset(things, 0, sizeof(things));
859
860 CHECK(!compileAndRun<int>(proc));
861
862 CHECK(things[0] == 3);
863 CHECK(things[1] == 1);
864 CHECK(things[2] == 2);
865 CHECK(things[3] == 4);
866 CHECK(things[4] == 4);
867 CHECK(things[5] == 5);
868}
869
870void testShuffleShiftAllRegs()
871{
872 B3::Procedure proc;
873 Code& code = proc.code();
874
875 const Vector<Reg>& regs = code.regsInPriorityOrder(GP);
876
877 BasicBlock* root = code.addBlock();
878 for (unsigned i = 0; i < regs.size(); ++i)
879 loadConstant(root, 35 + i, Tmp(regs[i]));
880 Inst& shuffle = root->append(Shuffle, nullptr);
881 for (unsigned i = 1; i < regs.size(); ++i)
882 shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Width32));
883
884 StackSlot* slot = code.addStackSlot(sizeof(int32_t) * regs.size(), StackSlotKind::Locked);
885 for (unsigned i = 0; i < regs.size(); ++i)
886 root->append(Move32, nullptr, Tmp(regs[i]), Arg::stack(slot, i * sizeof(int32_t)));
887
888 Vector<int32_t> things(regs.size(), 666);
889 Tmp base = code.newTmp(GP);
890 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), base);
891 for (unsigned i = 0; i < regs.size(); ++i) {
892 root->append(Move32, nullptr, Arg::stack(slot, i * sizeof(int32_t)), Tmp(GPRInfo::regT0));
893 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, i * sizeof(int32_t)));
894 }
895
896 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
897 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
898
899 CHECK(!compileAndRun<int>(proc));
900
901 CHECK(things[0] == 35);
902 for (unsigned i = 1; i < regs.size(); ++i)
903 CHECK(things[i] == 35 + static_cast<int32_t>(i) - 1);
904}
905
906void testShuffleRotateAllRegs()
907{
908 B3::Procedure proc;
909 Code& code = proc.code();
910
911 const Vector<Reg>& regs = code.regsInPriorityOrder(GP);
912
913 BasicBlock* root = code.addBlock();
914 for (unsigned i = 0; i < regs.size(); ++i)
915 loadConstant(root, 35 + i, Tmp(regs[i]));
916 Inst& shuffle = root->append(Shuffle, nullptr);
917 for (unsigned i = 1; i < regs.size(); ++i)
918 shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Width32));
919 shuffle.append(Tmp(regs.last()), Tmp(regs[0]), Arg::widthArg(Width32));
920
921 StackSlot* slot = code.addStackSlot(sizeof(int32_t) * regs.size(), StackSlotKind::Locked);
922 for (unsigned i = 0; i < regs.size(); ++i)
923 root->append(Move32, nullptr, Tmp(regs[i]), Arg::stack(slot, i * sizeof(int32_t)));
924
925 Vector<int32_t> things(regs.size(), 666);
926 Tmp base = code.newTmp(GP);
927 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), base);
928 for (unsigned i = 0; i < regs.size(); ++i) {
929 root->append(Move32, nullptr, Arg::stack(slot, i * sizeof(int32_t)), Tmp(GPRInfo::regT0));
930 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, i * sizeof(int32_t)));
931 }
932
933 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
934 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
935
936 CHECK(!compileAndRun<int>(proc));
937
938 CHECK(things[0] == 35 + static_cast<int32_t>(regs.size()) - 1);
939 for (unsigned i = 1; i < regs.size(); ++i)
940 CHECK(things[i] == 35 + static_cast<int32_t>(i) - 1);
941}
942
943void testShuffleSimpleSwap64()
944{
945 B3::Procedure proc;
946 Code& code = proc.code();
947
948 BasicBlock* root = code.addBlock();
949 loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
950 loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
951 loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
952 loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
953 root->append(
954 Shuffle, nullptr,
955 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width64),
956 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT2), Arg::widthArg(Width64));
957
958 int64_t things[4];
959 Tmp base = code.newTmp(GP);
960 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
961 root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
962 root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
963 root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
964 root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
965 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
966 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
967
968 memset(things, 0, sizeof(things));
969
970 CHECK(!compileAndRun<int>(proc));
971
972 CHECK(things[0] == 10000000000000000ll);
973 CHECK(things[1] == 20000000000000000ll);
974 CHECK(things[2] == 40000000000000000ll);
975 CHECK(things[3] == 30000000000000000ll);
976}
977
978void testShuffleSimpleShift64()
979{
980 B3::Procedure proc;
981 Code& code = proc.code();
982
983 BasicBlock* root = code.addBlock();
984 loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
985 loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
986 loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
987 loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
988 loadConstant(root, 50000000000000000ll, Tmp(GPRInfo::regT4));
989 root->append(
990 Shuffle, nullptr,
991 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width64),
992 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width64));
993
994 int64_t things[5];
995 Tmp base = code.newTmp(GP);
996 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
997 root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
998 root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
999 root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
1000 root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
1001 root->append(Move, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int64_t)));
1002 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1003 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1004
1005 memset(things, 0, sizeof(things));
1006
1007 CHECK(!compileAndRun<int>(proc));
1008
1009 CHECK(things[0] == 10000000000000000ll);
1010 CHECK(things[1] == 20000000000000000ll);
1011 CHECK(things[2] == 30000000000000000ll);
1012 CHECK(things[3] == 30000000000000000ll);
1013 CHECK(things[4] == 40000000000000000ll);
1014}
1015
1016void testShuffleSwapMixedWidth()
1017{
1018 B3::Procedure proc;
1019 Code& code = proc.code();
1020
1021 BasicBlock* root = code.addBlock();
1022 loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
1023 loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
1024 loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
1025 loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
1026 root->append(
1027 Shuffle, nullptr,
1028 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width32),
1029 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT2), Arg::widthArg(Width64));
1030
1031 int64_t things[4];
1032 Tmp base = code.newTmp(GP);
1033 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1034 root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
1035 root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
1036 root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
1037 root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
1038 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1039 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1040
1041 memset(things, 0, sizeof(things));
1042
1043 CHECK(!compileAndRun<int>(proc));
1044
1045 CHECK(things[0] == 10000000000000000ll);
1046 CHECK(things[1] == 20000000000000000ll);
1047 CHECK(things[2] == 40000000000000000ll);
1048 CHECK(things[3] == static_cast<uint32_t>(30000000000000000ll));
1049}
1050
1051void testShuffleShiftMixedWidth()
1052{
1053 B3::Procedure proc;
1054 Code& code = proc.code();
1055
1056 BasicBlock* root = code.addBlock();
1057 loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
1058 loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
1059 loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
1060 loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
1061 loadConstant(root, 50000000000000000ll, Tmp(GPRInfo::regT4));
1062 root->append(
1063 Shuffle, nullptr,
1064 Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Width64),
1065 Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Width32));
1066
1067 int64_t things[5];
1068 Tmp base = code.newTmp(GP);
1069 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1070 root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
1071 root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
1072 root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
1073 root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
1074 root->append(Move, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int64_t)));
1075 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1076 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1077
1078 memset(things, 0, sizeof(things));
1079
1080 CHECK(!compileAndRun<int>(proc));
1081
1082 CHECK(things[0] == 10000000000000000ll);
1083 CHECK(things[1] == 20000000000000000ll);
1084 CHECK(things[2] == 30000000000000000ll);
1085 CHECK(things[3] == 30000000000000000ll);
1086 CHECK(things[4] == static_cast<uint32_t>(40000000000000000ll));
1087}
1088
1089void testShuffleShiftMemory()
1090{
1091 B3::Procedure proc;
1092 Code& code = proc.code();
1093
1094 int32_t memory[2];
1095 memory[0] = 35;
1096 memory[1] = 36;
1097
1098 BasicBlock* root = code.addBlock();
1099 loadConstant(root, 1, Tmp(GPRInfo::regT0));
1100 loadConstant(root, 2, Tmp(GPRInfo::regT1));
1101 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
1102 root->append(
1103 Shuffle, nullptr,
1104 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
1105 Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int32_t)),
1106 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int32_t)), Arg::widthArg(Width32));
1107
1108 int32_t things[2];
1109 Tmp base = code.newTmp(GP);
1110 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1111 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
1112 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
1113 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1114 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1115
1116 memset(things, 0, sizeof(things));
1117
1118 CHECK(!compileAndRun<int>(proc));
1119
1120 CHECK(things[0] == 1);
1121 CHECK(things[1] == 1);
1122 CHECK(memory[0] == 35);
1123 CHECK(memory[1] == 35);
1124}
1125
1126void testShuffleShiftMemoryLong()
1127{
1128 B3::Procedure proc;
1129 Code& code = proc.code();
1130
1131 int32_t memory[2];
1132 memory[0] = 35;
1133 memory[1] = 36;
1134
1135 BasicBlock* root = code.addBlock();
1136 loadConstant(root, 1, Tmp(GPRInfo::regT0));
1137 loadConstant(root, 2, Tmp(GPRInfo::regT1));
1138 loadConstant(root, 3, Tmp(GPRInfo::regT2));
1139 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT3));
1140 root->append(
1141 Shuffle, nullptr,
1142
1143 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
1144
1145 Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT3), 0 * sizeof(int32_t)),
1146 Arg::widthArg(Width32),
1147
1148 Arg::addr(Tmp(GPRInfo::regT3), 0 * sizeof(int32_t)),
1149 Arg::addr(Tmp(GPRInfo::regT3), 1 * sizeof(int32_t)), Arg::widthArg(Width32),
1150
1151 Arg::addr(Tmp(GPRInfo::regT3), 1 * sizeof(int32_t)), Tmp(GPRInfo::regT2),
1152 Arg::widthArg(Width32));
1153
1154 int32_t things[3];
1155 Tmp base = code.newTmp(GP);
1156 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1157 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
1158 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
1159 root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
1160 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1161 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1162
1163 memset(things, 0, sizeof(things));
1164
1165 CHECK(!compileAndRun<int>(proc));
1166
1167 CHECK(things[0] == 1);
1168 CHECK(things[1] == 1);
1169 CHECK(things[2] == 36);
1170 CHECK(memory[0] == 2);
1171 CHECK(memory[1] == 35);
1172}
1173
1174void testShuffleShiftMemoryAllRegs()
1175{
1176 B3::Procedure proc;
1177 Code& code = proc.code();
1178
1179 int32_t memory[2];
1180 memory[0] = 35;
1181 memory[1] = 36;
1182
1183 Vector<Reg> regs = code.regsInPriorityOrder(GP);
1184 regs.removeFirst(Reg(GPRInfo::regT0));
1185
1186 BasicBlock* root = code.addBlock();
1187 for (unsigned i = 0; i < regs.size(); ++i)
1188 loadConstant(root, i + 1, Tmp(regs[i]));
1189 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
1190 Inst& shuffle = root->append(
1191 Shuffle, nullptr,
1192
1193 Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int32_t)),
1194 Arg::widthArg(Width32),
1195
1196 Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int32_t)),
1197 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int32_t)), Arg::widthArg(Width32),
1198
1199 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int32_t)), Tmp(regs[1]),
1200 Arg::widthArg(Width32));
1201
1202 for (unsigned i = 2; i < regs.size(); ++i)
1203 shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Width32));
1204
1205 Vector<int32_t> things(regs.size(), 666);
1206 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
1207 for (unsigned i = 0; i < regs.size(); ++i) {
1208 root->append(
1209 Move32, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int32_t)));
1210 }
1211 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1212 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1213
1214 CHECK(!compileAndRun<int>(proc));
1215
1216 CHECK(things[0] == 1);
1217 CHECK(things[1] == 36);
1218 for (unsigned i = 2; i < regs.size(); ++i)
1219 CHECK(things[i] == static_cast<int32_t>(i));
1220 CHECK(memory[0] == 1);
1221 CHECK(memory[1] == 35);
1222}
1223
1224void testShuffleShiftMemoryAllRegs64()
1225{
1226 B3::Procedure proc;
1227 Code& code = proc.code();
1228
1229 int64_t memory[2];
1230 memory[0] = 35000000000000ll;
1231 memory[1] = 36000000000000ll;
1232
1233 Vector<Reg> regs = code.regsInPriorityOrder(GP);
1234 regs.removeFirst(Reg(GPRInfo::regT0));
1235
1236 BasicBlock* root = code.addBlock();
1237 for (unsigned i = 0; i < regs.size(); ++i)
1238 loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
1239 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
1240 Inst& shuffle = root->append(
1241 Shuffle, nullptr,
1242
1243 Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1244 Arg::widthArg(Width64),
1245
1246 Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1247 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Width64),
1248
1249 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
1250 Arg::widthArg(Width64));
1251
1252 for (unsigned i = 2; i < regs.size(); ++i)
1253 shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Width64));
1254
1255 Vector<int64_t> things(regs.size(), 666);
1256 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
1257 for (unsigned i = 0; i < regs.size(); ++i) {
1258 root->append(
1259 Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
1260 }
1261 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1262 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1263
1264 CHECK(!compileAndRun<int>(proc));
1265
1266 CHECK(things[0] == 1000000000000ll);
1267 CHECK(things[1] == 36000000000000ll);
1268 for (unsigned i = 2; i < regs.size(); ++i)
1269 CHECK(things[i] == static_cast<int64_t>(i) * 1000000000000ll);
1270 CHECK(memory[0] == 1000000000000ll);
1271 CHECK(memory[1] == 35000000000000ll);
1272}
1273
1274int64_t combineHiLo(int64_t high, int64_t low)
1275{
1276 union {
1277 int64_t value;
1278 int32_t halves[2];
1279 } u;
1280 u.value = high;
1281 u.halves[0] = static_cast<int32_t>(low);
1282 return u.value;
1283}
1284
1285void testShuffleShiftMemoryAllRegsMixedWidth()
1286{
1287 B3::Procedure proc;
1288 Code& code = proc.code();
1289
1290 int64_t memory[2];
1291 memory[0] = 35000000000000ll;
1292 memory[1] = 36000000000000ll;
1293
1294 Vector<Reg> regs = code.regsInPriorityOrder(GP);
1295 regs.removeFirst(Reg(GPRInfo::regT0));
1296
1297 BasicBlock* root = code.addBlock();
1298 for (unsigned i = 0; i < regs.size(); ++i)
1299 loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
1300 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
1301 Inst& shuffle = root->append(
1302 Shuffle, nullptr,
1303
1304 Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1305 Arg::widthArg(Width32),
1306
1307 Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1308 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Width64),
1309
1310 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
1311 Arg::widthArg(Width32));
1312
1313 for (unsigned i = 2; i < regs.size(); ++i) {
1314 shuffle.append(
1315 Tmp(regs[i - 1]), Tmp(regs[i]),
1316 (i & 1) ? Arg::widthArg(Width32) : Arg::widthArg(Width64));
1317 }
1318
1319 Vector<int64_t> things(regs.size(), 666);
1320 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
1321 for (unsigned i = 0; i < regs.size(); ++i) {
1322 root->append(
1323 Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
1324 }
1325 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1326 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1327
1328 CHECK(!compileAndRun<int>(proc));
1329
1330 CHECK(things[0] == 1000000000000ll);
1331 CHECK(things[1] == static_cast<uint32_t>(36000000000000ll));
1332 for (unsigned i = 2; i < regs.size(); ++i) {
1333 int64_t value = static_cast<int64_t>(i) * 1000000000000ll;
1334 CHECK(things[i] == ((i & 1) ? static_cast<uint32_t>(value) : value));
1335 }
1336 CHECK(memory[0] == combineHiLo(35000000000000ll, 1000000000000ll));
1337 CHECK(memory[1] == 35000000000000ll);
1338}
1339
1340void testShuffleRotateMemory()
1341{
1342 B3::Procedure proc;
1343 Code& code = proc.code();
1344
1345 int32_t memory[2];
1346 memory[0] = 35;
1347 memory[1] = 36;
1348
1349 BasicBlock* root = code.addBlock();
1350 loadConstant(root, 1, Tmp(GPRInfo::regT0));
1351 loadConstant(root, 2, Tmp(GPRInfo::regT1));
1352 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
1353 root->append(
1354 Shuffle, nullptr,
1355
1356 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
1357
1358 Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int32_t)),
1359 Arg::widthArg(Width32),
1360
1361 Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int32_t)),
1362 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int32_t)), Arg::widthArg(Width32),
1363
1364 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int32_t)), Tmp(GPRInfo::regT0),
1365 Arg::widthArg(Width32));
1366
1367 int32_t things[2];
1368 Tmp base = code.newTmp(GP);
1369 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1370 root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
1371 root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
1372 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1373 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1374
1375 memset(things, 0, sizeof(things));
1376
1377 CHECK(!compileAndRun<int>(proc));
1378
1379 CHECK(things[0] == 36);
1380 CHECK(things[1] == 1);
1381 CHECK(memory[0] == 2);
1382 CHECK(memory[1] == 35);
1383}
1384
1385void testShuffleRotateMemory64()
1386{
1387 B3::Procedure proc;
1388 Code& code = proc.code();
1389
1390 int64_t memory[2];
1391 memory[0] = 35000000000000ll;
1392 memory[1] = 36000000000000ll;
1393
1394 BasicBlock* root = code.addBlock();
1395 loadConstant(root, 1000000000000ll, Tmp(GPRInfo::regT0));
1396 loadConstant(root, 2000000000000ll, Tmp(GPRInfo::regT1));
1397 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
1398 root->append(
1399 Shuffle, nullptr,
1400
1401 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width64),
1402
1403 Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
1404 Arg::widthArg(Width64),
1405
1406 Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
1407 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Arg::widthArg(Width64),
1408
1409 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Tmp(GPRInfo::regT0),
1410 Arg::widthArg(Width64));
1411
1412 int64_t things[2];
1413 Tmp base = code.newTmp(GP);
1414 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1415 root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
1416 root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
1417 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1418 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1419
1420 memset(things, 0, sizeof(things));
1421
1422 CHECK(!compileAndRun<int>(proc));
1423
1424 CHECK(things[0] == 36000000000000ll);
1425 CHECK(things[1] == 1000000000000ll);
1426 CHECK(memory[0] == 2000000000000ll);
1427 CHECK(memory[1] == 35000000000000ll);
1428}
1429
1430void testShuffleRotateMemoryMixedWidth()
1431{
1432 B3::Procedure proc;
1433 Code& code = proc.code();
1434
1435 int64_t memory[2];
1436 memory[0] = 35000000000000ll;
1437 memory[1] = 36000000000000ll;
1438
1439 BasicBlock* root = code.addBlock();
1440 loadConstant(root, 1000000000000ll, Tmp(GPRInfo::regT0));
1441 loadConstant(root, 2000000000000ll, Tmp(GPRInfo::regT1));
1442 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
1443 root->append(
1444 Shuffle, nullptr,
1445
1446 Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Width32),
1447
1448 Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
1449 Arg::widthArg(Width64),
1450
1451 Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
1452 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Arg::widthArg(Width32),
1453
1454 Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Tmp(GPRInfo::regT0),
1455 Arg::widthArg(Width64));
1456
1457 int64_t things[2];
1458 Tmp base = code.newTmp(GP);
1459 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1460 root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
1461 root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
1462 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1463 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1464
1465 memset(things, 0, sizeof(things));
1466
1467 CHECK(!compileAndRun<int>(proc));
1468
1469 CHECK(things[0] == 36000000000000ll);
1470 CHECK(things[1] == static_cast<uint32_t>(1000000000000ll));
1471 CHECK(memory[0] == 2000000000000ll);
1472 CHECK(memory[1] == combineHiLo(36000000000000ll, 35000000000000ll));
1473}
1474
1475void testShuffleRotateMemoryAllRegs64()
1476{
1477 B3::Procedure proc;
1478 Code& code = proc.code();
1479
1480 int64_t memory[2];
1481 memory[0] = 35000000000000ll;
1482 memory[1] = 36000000000000ll;
1483
1484 Vector<Reg> regs = code.regsInPriorityOrder(GP);
1485 regs.removeFirst(Reg(GPRInfo::regT0));
1486
1487 BasicBlock* root = code.addBlock();
1488 for (unsigned i = 0; i < regs.size(); ++i)
1489 loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
1490 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
1491 Inst& shuffle = root->append(
1492 Shuffle, nullptr,
1493
1494 Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1495 Arg::widthArg(Width64),
1496
1497 Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1498 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Width64),
1499
1500 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
1501 Arg::widthArg(Width64),
1502
1503 regs.last(), regs[0], Arg::widthArg(Width64));
1504
1505 for (unsigned i = 2; i < regs.size(); ++i)
1506 shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Width64));
1507
1508 Vector<int64_t> things(regs.size(), 666);
1509 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
1510 for (unsigned i = 0; i < regs.size(); ++i) {
1511 root->append(
1512 Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
1513 }
1514 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1515 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1516
1517 CHECK(!compileAndRun<int>(proc));
1518
1519 CHECK(things[0] == static_cast<int64_t>(regs.size()) * 1000000000000ll);
1520 CHECK(things[1] == 36000000000000ll);
1521 for (unsigned i = 2; i < regs.size(); ++i)
1522 CHECK(things[i] == static_cast<int64_t>(i) * 1000000000000ll);
1523 CHECK(memory[0] == 1000000000000ll);
1524 CHECK(memory[1] == 35000000000000ll);
1525}
1526
1527void testShuffleRotateMemoryAllRegsMixedWidth()
1528{
1529 B3::Procedure proc;
1530 Code& code = proc.code();
1531
1532 int64_t memory[2];
1533 memory[0] = 35000000000000ll;
1534 memory[1] = 36000000000000ll;
1535
1536 Vector<Reg> regs = code.regsInPriorityOrder(GP);
1537 regs.removeFirst(Reg(GPRInfo::regT0));
1538
1539 BasicBlock* root = code.addBlock();
1540 for (unsigned i = 0; i < regs.size(); ++i)
1541 loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
1542 root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
1543 Inst& shuffle = root->append(
1544 Shuffle, nullptr,
1545
1546 Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1547 Arg::widthArg(Width32),
1548
1549 Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
1550 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Width64),
1551
1552 Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
1553 Arg::widthArg(Width32),
1554
1555 regs.last(), regs[0], Arg::widthArg(Width32));
1556
1557 for (unsigned i = 2; i < regs.size(); ++i)
1558 shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Width64));
1559
1560 Vector<int64_t> things(regs.size(), 666);
1561 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
1562 for (unsigned i = 0; i < regs.size(); ++i) {
1563 root->append(
1564 Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
1565 }
1566 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1567 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1568
1569 CHECK(!compileAndRun<int>(proc));
1570
1571 CHECK(things[0] == static_cast<uint32_t>(static_cast<int64_t>(regs.size()) * 1000000000000ll));
1572 CHECK(things[1] == static_cast<uint32_t>(36000000000000ll));
1573 for (unsigned i = 2; i < regs.size(); ++i)
1574 CHECK(things[i] == static_cast<int64_t>(i) * 1000000000000ll);
1575 CHECK(memory[0] == combineHiLo(35000000000000ll, 1000000000000ll));
1576 CHECK(memory[1] == 35000000000000ll);
1577}
1578
1579void testShuffleSwapDouble()
1580{
1581 B3::Procedure proc;
1582 Code& code = proc.code();
1583
1584 BasicBlock* root = code.addBlock();
1585 loadDoubleConstant(root, 1, Tmp(FPRInfo::fpRegT0), Tmp(GPRInfo::regT0));
1586 loadDoubleConstant(root, 2, Tmp(FPRInfo::fpRegT1), Tmp(GPRInfo::regT0));
1587 loadDoubleConstant(root, 3, Tmp(FPRInfo::fpRegT2), Tmp(GPRInfo::regT0));
1588 loadDoubleConstant(root, 4, Tmp(FPRInfo::fpRegT3), Tmp(GPRInfo::regT0));
1589 root->append(
1590 Shuffle, nullptr,
1591 Tmp(FPRInfo::fpRegT2), Tmp(FPRInfo::fpRegT3), Arg::widthArg(Width64),
1592 Tmp(FPRInfo::fpRegT3), Tmp(FPRInfo::fpRegT2), Arg::widthArg(Width64));
1593
1594 double things[4];
1595 Tmp base = code.newTmp(GP);
1596 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1597 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT0), Arg::addr(base, 0 * sizeof(double)));
1598 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT1), Arg::addr(base, 1 * sizeof(double)));
1599 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT2), Arg::addr(base, 2 * sizeof(double)));
1600 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT3), Arg::addr(base, 3 * sizeof(double)));
1601 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1602 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1603
1604 memset(things, 0, sizeof(things));
1605
1606 CHECK(!compileAndRun<int>(proc));
1607
1608 CHECK(things[0] == 1);
1609 CHECK(things[1] == 2);
1610 CHECK(things[2] == 4);
1611 CHECK(things[3] == 3);
1612}
1613
1614void testShuffleShiftDouble()
1615{
1616 B3::Procedure proc;
1617 Code& code = proc.code();
1618
1619 BasicBlock* root = code.addBlock();
1620 loadDoubleConstant(root, 1, Tmp(FPRInfo::fpRegT0), Tmp(GPRInfo::regT0));
1621 loadDoubleConstant(root, 2, Tmp(FPRInfo::fpRegT1), Tmp(GPRInfo::regT0));
1622 loadDoubleConstant(root, 3, Tmp(FPRInfo::fpRegT2), Tmp(GPRInfo::regT0));
1623 loadDoubleConstant(root, 4, Tmp(FPRInfo::fpRegT3), Tmp(GPRInfo::regT0));
1624 root->append(
1625 Shuffle, nullptr,
1626 Tmp(FPRInfo::fpRegT2), Tmp(FPRInfo::fpRegT3), Arg::widthArg(Width64));
1627
1628 double things[4];
1629 Tmp base = code.newTmp(GP);
1630 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1631 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT0), Arg::addr(base, 0 * sizeof(double)));
1632 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT1), Arg::addr(base, 1 * sizeof(double)));
1633 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT2), Arg::addr(base, 2 * sizeof(double)));
1634 root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT3), Arg::addr(base, 3 * sizeof(double)));
1635 root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
1636 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1637
1638 memset(things, 0, sizeof(things));
1639
1640 CHECK(!compileAndRun<int>(proc));
1641
1642 CHECK(things[0] == 1);
1643 CHECK(things[1] == 2);
1644 CHECK(things[2] == 3);
1645 CHECK(things[3] == 3);
1646}
1647
1648#if CPU(X86) || CPU(X86_64)
1649void testX86VMULSD()
1650{
1651 B3::Procedure proc;
1652 Code& code = proc.code();
1653
1654 BasicBlock* root = code.addBlock();
1655 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Tmp(FPRInfo::argumentFPR1), Tmp(FPRInfo::argumentFPR2));
1656 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR2), Tmp(FPRInfo::returnValueFPR));
1657 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1658
1659 CHECK(compileAndRun<double>(proc, 2.4, 4.2, pureNaN()) == 2.4 * 4.2);
1660}
1661
1662void testX86VMULSDDestRex()
1663{
1664 B3::Procedure proc;
1665 Code& code = proc.code();
1666
1667 BasicBlock* root = code.addBlock();
1668 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Tmp(FPRInfo::argumentFPR1), Tmp(X86Registers::xmm15));
1669 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1670 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1671
1672 CHECK(compileAndRun<double>(proc, 2.4, 4.2, pureNaN()) == 2.4 * 4.2);
1673}
1674
1675void testX86VMULSDOp1DestRex()
1676{
1677 B3::Procedure proc;
1678 Code& code = proc.code();
1679
1680 BasicBlock* root = code.addBlock();
1681 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm14));
1682 root->append(MulDouble, nullptr, Tmp(X86Registers::xmm14), Tmp(FPRInfo::argumentFPR1), Tmp(X86Registers::xmm15));
1683 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1684 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1685
1686 CHECK(compileAndRun<double>(proc, 2.4, 4.2, pureNaN()) == 2.4 * 4.2);
1687}
1688
1689void testX86VMULSDOp2DestRex()
1690{
1691 B3::Procedure proc;
1692 Code& code = proc.code();
1693
1694 BasicBlock* root = code.addBlock();
1695 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR1), Tmp(X86Registers::xmm14));
1696 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm14), Tmp(X86Registers::xmm15));
1697 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1698 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1699
1700 CHECK(compileAndRun<double>(proc, 2.4, 4.2, pureNaN()) == 2.4 * 4.2);
1701}
1702
1703void testX86VMULSDOpsDestRex()
1704{
1705 B3::Procedure proc;
1706 Code& code = proc.code();
1707
1708 BasicBlock* root = code.addBlock();
1709 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm14));
1710 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR1), Tmp(X86Registers::xmm13));
1711 root->append(MulDouble, nullptr, Tmp(X86Registers::xmm14), Tmp(X86Registers::xmm13), Tmp(X86Registers::xmm15));
1712 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1713 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1714
1715 CHECK(compileAndRun<double>(proc, 2.4, 4.2, pureNaN()) == 2.4 * 4.2);
1716}
1717
1718void testX86VMULSDAddr()
1719{
1720 B3::Procedure proc;
1721 Code& code = proc.code();
1722
1723 BasicBlock* root = code.addBlock();
1724 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Arg::addr(Tmp(GPRInfo::argumentGPR0), - 16), Tmp(FPRInfo::argumentFPR2));
1725 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR2), Tmp(FPRInfo::returnValueFPR));
1726 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1727
1728 double secondArg = 4.2;
1729 CHECK(compileAndRun<double>(proc, 2.4, &secondArg + 2, pureNaN()) == 2.4 * 4.2);
1730}
1731
1732void testX86VMULSDAddrOpRexAddr()
1733{
1734 B3::Procedure proc;
1735 Code& code = proc.code();
1736
1737 BasicBlock* root = code.addBlock();
1738 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR0), Tmp(X86Registers::r13));
1739 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Arg::addr(Tmp(X86Registers::r13), - 16), Tmp(FPRInfo::argumentFPR2));
1740 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR2), Tmp(FPRInfo::returnValueFPR));
1741 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1742
1743 double secondArg = 4.2;
1744 CHECK(compileAndRun<double>(proc, 2.4, &secondArg + 2, pureNaN()) == 2.4 * 4.2);
1745}
1746
1747void testX86VMULSDDestRexAddr()
1748{
1749 B3::Procedure proc;
1750 Code& code = proc.code();
1751
1752 BasicBlock* root = code.addBlock();
1753 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Arg::addr(Tmp(GPRInfo::argumentGPR0), 16), Tmp(X86Registers::xmm15));
1754 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1755 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1756
1757 double secondArg = 4.2;
1758 CHECK(compileAndRun<double>(proc, 2.4, &secondArg - 2, pureNaN()) == 2.4 * 4.2);
1759}
1760
1761void testX86VMULSDRegOpDestRexAddr()
1762{
1763 B3::Procedure proc;
1764 Code& code = proc.code();
1765
1766 BasicBlock* root = code.addBlock();
1767 root->append(MoveDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm14));
1768 root->append(MulDouble, nullptr, Arg::addr(Tmp(GPRInfo::argumentGPR0)), Tmp(X86Registers::xmm14), Tmp(X86Registers::xmm15));
1769 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1770 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1771
1772 double secondArg = 4.2;
1773 CHECK(compileAndRun<double>(proc, 2.4, &secondArg, pureNaN()) == 2.4 * 4.2);
1774}
1775
1776void testX86VMULSDAddrOpDestRexAddr()
1777{
1778 B3::Procedure proc;
1779 Code& code = proc.code();
1780
1781 BasicBlock* root = code.addBlock();
1782 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR0), Tmp(X86Registers::r13));
1783 root->append(MulDouble, nullptr, Tmp(FPRInfo::argumentFPR0), Arg::addr(Tmp(X86Registers::r13), 8), Tmp(X86Registers::xmm15));
1784 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm15), Tmp(FPRInfo::returnValueFPR));
1785 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1786
1787 double secondArg = 4.2;
1788 CHECK(compileAndRun<double>(proc, 2.4, &secondArg - 1, pureNaN()) == 2.4 * 4.2);
1789}
1790
1791void testX86VMULSDBaseNeedsRex()
1792{
1793 B3::Procedure proc;
1794 Code& code = proc.code();
1795
1796 BasicBlock* root = code.addBlock();
1797 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR0), Tmp(X86Registers::r13));
1798 root->append(MulDouble, nullptr, Arg::index(Tmp(X86Registers::r13), Tmp(GPRInfo::argumentGPR1)), Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm0));
1799 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm0), Tmp(FPRInfo::returnValueFPR));
1800 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1801
1802 double secondArg = 4.2;
1803 uint64_t index = 8;
1804 CHECK(compileAndRun<double>(proc, 2.4, &secondArg - 1, index, pureNaN()) == 2.4 * 4.2);
1805}
1806
1807void testX86VMULSDIndexNeedsRex()
1808{
1809 B3::Procedure proc;
1810 Code& code = proc.code();
1811
1812 BasicBlock* root = code.addBlock();
1813 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR1), Tmp(X86Registers::r13));
1814 root->append(MulDouble, nullptr, Arg::index(Tmp(GPRInfo::argumentGPR0), Tmp(X86Registers::r13)), Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm0));
1815 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm0), Tmp(FPRInfo::returnValueFPR));
1816 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1817
1818 double secondArg = 4.2;
1819 uint64_t index = - 8;
1820 CHECK(compileAndRun<double>(proc, 2.4, &secondArg + 1, index, pureNaN()) == 2.4 * 4.2);
1821}
1822
1823void testX86VMULSDBaseIndexNeedRex()
1824{
1825 B3::Procedure proc;
1826 Code& code = proc.code();
1827
1828 BasicBlock* root = code.addBlock();
1829 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR0), Tmp(X86Registers::r12));
1830 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR1), Tmp(X86Registers::r13));
1831 root->append(MulDouble, nullptr, Arg::index(Tmp(X86Registers::r12), Tmp(X86Registers::r13)), Tmp(FPRInfo::argumentFPR0), Tmp(X86Registers::xmm0));
1832 root->append(MoveDouble, nullptr, Tmp(X86Registers::xmm0), Tmp(FPRInfo::returnValueFPR));
1833 root->append(RetDouble, nullptr, Tmp(FPRInfo::returnValueFPR));
1834
1835 double secondArg = 4.2;
1836 uint64_t index = 16;
1837 CHECK(compileAndRun<double>(proc, 2.4, &secondArg - 2, index, pureNaN()) == 2.4 * 4.2);
1838}
1839#endif // #if CPU(X86) || CPU(X86_64)
1840
1841#if CPU(ARM64)
1842void testInvalidateCachedTempRegisters()
1843{
1844 B3::Procedure proc;
1845 Code& code = proc.code();
1846 BasicBlock* root = code.addBlock();
1847
1848 int32_t things[4];
1849 things[0] = 0x12000000;
1850 things[1] = 0x340000;
1851 things[2] = 0x5600;
1852 things[3] = 0x78;
1853 Tmp base = code.newTmp(GP);
1854 GPRReg tmp = GPRInfo::regT1;
1855 proc.pinRegister(tmp);
1856
1857 root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
1858
1859 B3::BasicBlock* patchPoint1Root = proc.addBlock();
1860 B3::Air::Special* patchpointSpecial = code.addSpecial(makeUnique<B3::PatchpointSpecial>());
1861
1862 // In Patchpoint, Load things[0] -> tmp. This will materialize the address in x17 (dataMemoryRegister).
1863 B3::PatchpointValue* patchpoint1 = patchPoint1Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
1864 patchpoint1->clobber(RegisterSet::macroScratchRegisters());
1865 patchpoint1->setGenerator(
1866 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1867 AllowMacroScratchRegisterUsage allowScratch(jit);
1868 jit.load32(&things, tmp);
1869 });
1870 root->append(Patch, patchpoint1, Arg::special(patchpointSpecial));
1871
1872 // Load things[1] -> x17, trashing dataMemoryRegister.
1873 root->append(Move32, nullptr, Arg::addr(base, 1 * sizeof(int32_t)), Tmp(ARM64Registers::x17));
1874 root->append(Add32, nullptr, Tmp(tmp), Tmp(ARM64Registers::x17), Tmp(GPRInfo::returnValueGPR));
1875
1876 // In Patchpoint, Load things[2] -> tmp. This should not reuse the prior contents of x17.
1877 B3::BasicBlock* patchPoint2Root = proc.addBlock();
1878 B3::PatchpointValue* patchpoint2 = patchPoint2Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
1879 patchpoint2->clobber(RegisterSet::macroScratchRegisters());
1880 patchpoint2->setGenerator(
1881 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1882 AllowMacroScratchRegisterUsage allowScratch(jit);
1883 jit.load32(&things[2], tmp);
1884 });
1885 root->append(Patch, patchpoint2, Arg::special(patchpointSpecial));
1886
1887 root->append(Add32, nullptr, Tmp(tmp), Tmp(GPRInfo::returnValueGPR), Tmp(GPRInfo::returnValueGPR));
1888
1889 // In patchpoint, Store 0x78 -> things[3].
1890 // This will use and cache both x16 (dataMemoryRegister) and x17 (dataTempRegister).
1891 B3::BasicBlock* patchPoint3Root = proc.addBlock();
1892 B3::PatchpointValue* patchpoint3 = patchPoint3Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
1893 patchpoint3->clobber(RegisterSet::macroScratchRegisters());
1894 patchpoint3->setGenerator(
1895 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1896 AllowMacroScratchRegisterUsage allowScratch(jit);
1897 jit.store32(CCallHelpers::TrustedImm32(0x78), &things[3]);
1898 });
1899 root->append(Patch, patchpoint3, Arg::special(patchpointSpecial));
1900
1901 // Set x16 to 0xdead, trashing x16.
1902 root->append(Move, nullptr, Arg::bigImm(0xdead), Tmp(ARM64Registers::x16));
1903 root->append(Xor32, nullptr, Tmp(ARM64Registers::x16), Tmp(GPRInfo::returnValueGPR));
1904
1905 // In patchpoint, again Store 0x78 -> things[3].
1906 // This should rematerialize both x16 (dataMemoryRegister) and x17 (dataTempRegister).
1907 B3::BasicBlock* patchPoint4Root = proc.addBlock();
1908 B3::PatchpointValue* patchpoint4 = patchPoint4Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
1909 patchpoint4->clobber(RegisterSet::macroScratchRegisters());
1910 patchpoint4->setGenerator(
1911 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1912 AllowMacroScratchRegisterUsage allowScratch(jit);
1913 jit.store32(CCallHelpers::TrustedImm32(0x78), &things[3]);
1914 });
1915 root->append(Patch, patchpoint4, Arg::special(patchpointSpecial));
1916
1917 root->append(Move, nullptr, Arg::bigImm(0xdead), Tmp(tmp));
1918 root->append(Xor32, nullptr, Tmp(tmp), Tmp(GPRInfo::returnValueGPR));
1919 root->append(Move32, nullptr, Arg::addr(base, 3 * sizeof(int32_t)), Tmp(tmp));
1920 root->append(Add32, nullptr, Tmp(tmp), Tmp(GPRInfo::returnValueGPR), Tmp(GPRInfo::returnValueGPR));
1921 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1922
1923 int32_t r = compileAndRun<int32_t>(proc);
1924 CHECK(r == 0x12345678);
1925}
1926#endif // #if CPU(ARM64)
1927
1928void testArgumentRegPinned()
1929{
1930 B3::Procedure proc;
1931 Code& code = proc.code();
1932 GPRReg pinned = GPRInfo::argumentGPR0;
1933 proc.pinRegister(pinned);
1934
1935 B3::Air::Special* patchpointSpecial = code.addSpecial(makeUnique<B3::PatchpointSpecial>());
1936
1937 B3::BasicBlock* b3Root = proc.addBlock();
1938 B3::PatchpointValue* patchpoint = b3Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
1939 patchpoint->clobber(RegisterSet(pinned));
1940 patchpoint->setGenerator(
1941 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1942 jit.move(CCallHelpers::TrustedImm32(42), pinned);
1943 });
1944
1945 BasicBlock* root = code.addBlock();
1946
1947 Tmp t1 = code.newTmp(GP);
1948 Tmp t2 = code.newTmp(GP);
1949
1950 root->append(Move, nullptr, Tmp(pinned), t1);
1951 root->append(Patch, patchpoint, Arg::special(patchpointSpecial));
1952 root->append(Move, nullptr, Tmp(pinned), t2);
1953 root->append(Add32, nullptr, t1, t2, Tmp(GPRInfo::returnValueGPR));
1954 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1955
1956 int32_t r = compileAndRun<int32_t>(proc, 10);
1957 CHECK(r == 10 + 42);
1958}
1959
1960void testArgumentRegPinned2()
1961{
1962 B3::Procedure proc;
1963 Code& code = proc.code();
1964 GPRReg pinned = GPRInfo::argumentGPR0;
1965 proc.pinRegister(pinned);
1966
1967 B3::Air::Special* patchpointSpecial = code.addSpecial(makeUnique<B3::PatchpointSpecial>());
1968
1969 B3::BasicBlock* b3Root = proc.addBlock();
1970 B3::PatchpointValue* patchpoint = b3Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
1971 patchpoint->clobber({ });
1972 patchpoint->setGenerator(
1973 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
1974 jit.move(CCallHelpers::TrustedImm32(42), pinned);
1975 });
1976
1977 BasicBlock* root = code.addBlock();
1978
1979 Tmp t1 = code.newTmp(GP);
1980 Tmp t2 = code.newTmp(GP);
1981
1982 // Since the patchpoint does not claim to clobber the pinned register,
1983 // the register allocator is allowed to either coalesce the first move,
1984 // the second move, or neither. The allowed results are:
1985 // - No move coalesced: 52
1986 // - The first move is coalesced: 84
1987 // - The second move is coalesced: 52
1988 root->append(Move, nullptr, Tmp(pinned), t1);
1989 root->append(Patch, patchpoint, Arg::special(patchpointSpecial));
1990 root->append(Move, nullptr, Tmp(pinned), t2);
1991 root->append(Add32, nullptr, t1, t2, Tmp(GPRInfo::returnValueGPR));
1992 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
1993
1994 int32_t r = compileAndRun<int32_t>(proc, 10);
1995 CHECK(r == 52 || r == 84);
1996}
1997
1998void testArgumentRegPinned3()
1999{
2000 B3::Procedure proc;
2001 Code& code = proc.code();
2002 GPRReg pinned = GPRInfo::argumentGPR0;
2003 proc.pinRegister(pinned);
2004
2005 B3::Air::Special* patchpointSpecial = code.addSpecial(makeUnique<B3::PatchpointSpecial>());
2006
2007 B3::BasicBlock* b3Root = proc.addBlock();
2008 B3::PatchpointValue* patchpoint = b3Root->appendNew<B3::PatchpointValue>(proc, B3::Void, B3::Origin());
2009 patchpoint->clobber(RegisterSet(pinned));
2010 patchpoint->setGenerator(
2011 [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
2012 jit.move(CCallHelpers::TrustedImm32(42), pinned);
2013 });
2014
2015 BasicBlock* root = code.addBlock();
2016
2017 Tmp t1 = code.newTmp(GP);
2018 Tmp t2 = code.newTmp(GP);
2019 Tmp t3 = code.newTmp(GP);
2020
2021 root->append(Move, nullptr, Tmp(pinned), t1);
2022 root->append(Patch, patchpoint, Arg::special(patchpointSpecial));
2023 root->append(Move, nullptr, Tmp(pinned), t2);
2024 root->append(Patch, patchpoint, Arg::special(patchpointSpecial));
2025 root->append(Move, nullptr, Tmp(pinned), t3);
2026 root->append(Add32, nullptr, t1, t2, Tmp(GPRInfo::returnValueGPR));
2027 root->append(Add32, nullptr, Tmp(GPRInfo::returnValueGPR), t3, Tmp(GPRInfo::returnValueGPR));
2028 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
2029
2030 int32_t r = compileAndRun<int32_t>(proc, 10);
2031 CHECK(r == 10 + 42 + 42);
2032}
2033
2034void testLea64()
2035{
2036 B3::Procedure proc;
2037 Code& code = proc.code();
2038
2039 BasicBlock* root = code.addBlock();
2040
2041 int64_t a = 0x11223344;
2042 int64_t b = 1 << 13;
2043
2044 root->append(Lea64, nullptr, Arg::addr(Tmp(GPRInfo::argumentGPR0), b), Tmp(GPRInfo::returnValueGPR));
2045 root->append(Ret64, nullptr, Tmp(GPRInfo::returnValueGPR));
2046
2047 int64_t r = compileAndRun<int64_t>(proc, a);
2048 CHECK(r == a + b);
2049}
2050
2051void testLea32()
2052{
2053 B3::Procedure proc;
2054 Code& code = proc.code();
2055
2056 BasicBlock* root = code.addBlock();
2057
2058 int32_t a = 0x11223344;
2059 int32_t b = 1 << 13;
2060
2061 root->append(Lea32, nullptr, Arg::addr(Tmp(GPRInfo::argumentGPR0), b), Tmp(GPRInfo::returnValueGPR));
2062 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
2063
2064 int32_t r = compileAndRun<int32_t>(proc, a);
2065 CHECK(r == a + b);
2066}
2067
2068inline Vector<String> matchAll(const CString& source, std::regex regex)
2069{
2070 Vector<String> matches;
2071 std::smatch match;
2072 for (std::string str = source.data(); std::regex_search(str, match, regex);) {
2073 ASSERT(match.size() == 1);
2074 str = match.suffix();
2075 matches.append(match[0].str().c_str());
2076 }
2077 return matches;
2078}
2079
2080void testElideSimpleMove()
2081{
2082 for (unsigned tmpCount = 1; tmpCount < 100; tmpCount++) {
2083 B3::Procedure proc;
2084 Code& code = proc.code();
2085
2086 BasicBlock* root = code.addBlock();
2087
2088 Tmp tmp = code.newTmp(B3::GP);
2089 root->append(Move, nullptr, Tmp(GPRInfo::argumentGPR0), tmp);
2090 for (unsigned i = 0; i < tmpCount; i++) {
2091 Tmp newTmp = code.newTmp(B3::GP);
2092 root->append(Move, nullptr, tmp, newTmp);
2093 tmp = newTmp;
2094 }
2095 root->append(Move, nullptr, tmp, Tmp(GPRInfo::returnValueGPR));
2096 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
2097
2098 auto compilation = compile(proc);
2099 CString disassembly = compilation->disassembly();
2100 std::regex findRRMove(isARM64() ? "mov r\\d+, r\\d+\\n" : "mov %\\w+, %\\w+\\n");
2101 auto result = matchAll(disassembly, findRRMove);
2102 // sp -> fp; arg0 -> ret0; fp -> sp
2103 // fp -> sp only happens in O0 because we don't actually need to move the stack in general.
2104 CHECK(result.size() == 2 + !Options::defaultB3OptLevel());
2105 }
2106}
2107
2108void testElideHandlesEarlyClobber()
2109{
2110 B3::Procedure proc;
2111 Code& code = proc.code();
2112
2113 BasicBlock* root = code.addBlock();
2114
2115 const unsigned tmpCount = RegisterSet::allGPRs().numberOfSetRegisters() * 2;
2116 Vector<Tmp> tmps(tmpCount);
2117 for (unsigned i = 0; i < tmpCount; ++i) {
2118 tmps[i] = code.newTmp(B3::GP);
2119 root->append(Move, nullptr, Arg::imm(i), tmps[i]);
2120 }
2121
2122 RegisterSet registers = RegisterSet::allGPRs();
2123 registers.exclude(RegisterSet::reservedHardwareRegisters());
2124 registers.exclude(RegisterSet::stackRegisters());
2125 Reg firstCalleeSave;
2126 Reg lastCalleeSave;
2127 auto* patch = proc.add<B3::PatchpointValue>(B3::Int32, B3::Origin());
2128 patch->clobberEarly(registers);
2129 for (Reg reg : registers) {
2130 if (!firstCalleeSave)
2131 firstCalleeSave = reg;
2132 lastCalleeSave = reg;
2133 }
2134 ASSERT(firstCalleeSave != lastCalleeSave);
2135 patch->earlyClobbered().clear(firstCalleeSave);
2136 patch->resultConstraints.append({ B3::ValueRep::reg(firstCalleeSave) });
2137 patch->earlyClobbered().clear(lastCalleeSave);
2138 patch->clobber(RegisterSet(lastCalleeSave));
2139
2140 patch->setGenerator([=] (CCallHelpers& jit, const JSC::B3::StackmapGenerationParams&) {
2141 jit.probe([=] (Probe::Context& context) {
2142 for (Reg reg : registers)
2143 context.gpr(reg.gpr()) = 0;
2144 });
2145 });
2146
2147 Inst inst(Patch, patch, Arg::special(code.addSpecial(WTF::makeUnique<JSC::B3::PatchpointSpecial>())));
2148 inst.args.append(Tmp(firstCalleeSave));
2149 root->appendInst(WTFMove(inst));
2150
2151 Tmp result = code.newTmp(B3::GP);
2152 root->append(Move, nullptr, tmps[0], result);
2153 for (Tmp tmp : tmps)
2154 root->append(Add32, nullptr, tmp, result);
2155
2156 root->append(Move, nullptr, result, Tmp(GPRInfo::returnValueGPR));
2157 root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
2158
2159 auto runResult = compileAndRun<uint32_t>(proc);
2160 CHECK(runResult == (tmpCount * (tmpCount - 1)) / 2);
2161}
2162
2163void testElideMoveThenRealloc()
2164{
2165 RegisterSet registers = RegisterSet::allGPRs();
2166 registers.exclude(RegisterSet::stackRegisters());
2167 registers.exclude(RegisterSet::reservedHardwareRegisters());
2168
2169 for (Reg reg : registers) {
2170 B3::Procedure proc;
2171 Code& code = proc.code();
2172
2173 BasicBlock* root = code.addBlock();
2174 BasicBlock* taken = code.addBlock();
2175 BasicBlock* notTaken = code.addBlock();
2176 BasicBlock* notTakenReturn = code.addBlock();
2177 BasicBlock* ret = code.addBlock();
2178 BasicBlock* continuation = code.addBlock();
2179
2180 Tmp tmp = code.newTmp(B3::GP);
2181 {
2182 root->append(Move, nullptr, Arg::imm(1), Tmp(reg));
2183
2184 root->append(BranchTest32, nullptr, Arg::resCond(MacroAssembler::NonZero), Tmp(reg), Arg::bitImm(-1));
2185 root->setSuccessors(taken, notTaken);
2186 }
2187
2188 {
2189 taken->append(Jump, nullptr);
2190 taken->setSuccessors(continuation);
2191 }
2192
2193 {
2194 notTaken->append(BranchTest32, nullptr, Arg::resCond(MacroAssembler::NonZero), Tmp(reg), Arg::bitImm(-1));
2195 notTaken->setSuccessors(continuation, notTakenReturn);
2196 }
2197
2198 {
2199 tmp = code.newTmp(B3::GP);
2200 continuation->append(Move, nullptr, Arg::imm(42), tmp);
2201 continuation->append(BranchTest32, nullptr, Arg::resCond(MacroAssembler::NonZero), tmp, Arg::bitImm(-1));
2202 continuation->setSuccessors(ret, notTakenReturn);
2203 }
2204
2205 {
2206 tmp = code.newTmp(B3::GP);
2207 ret->append(Move, nullptr, Arg::imm(42), tmp);
2208 ret->append(Move, nullptr, tmp, Tmp(reg));
2209 ret->append(Move, nullptr, Tmp(reg), Tmp(GPRInfo::returnValueGPR));
2210 ret->append(Add32, nullptr, Tmp(reg), Tmp(reg));
2211 ret->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
2212 }
2213
2214 {
2215 notTakenReturn->append(Move, nullptr, Tmp(reg), Tmp(GPRInfo::returnValueGPR));
2216 notTakenReturn->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
2217 }
2218
2219 code.resetReachability();
2220 auto runResult = compileAndRun<uint32_t>(proc);
2221 CHECK(runResult == 42 + (42 * (reg == GPRInfo::returnValueGPR)));
2222 }
2223}
2224
2225#define PREFIX "O", Options::defaultB3OptLevel(), ": "
2226
2227#define RUN(test) do { \
2228 if (!shouldRun(#test)) \
2229 break; \
2230 tasks.append( \
2231 createSharedTask<void()>( \
2232 [&] () { \
2233 dataLog(PREFIX #test "...\n"); \
2234 test; \
2235 dataLog(PREFIX #test ": OK!\n"); \
2236 })); \
2237 } while (false);
2238
2239void run(const char* filter)
2240{
2241 Deque<RefPtr<SharedTask<void()>>> tasks;
2242
2243 auto shouldRun = [&] (const char* testName) -> bool {
2244 return !filter || WTF::findIgnoringASCIICaseWithoutLength(testName, filter) != WTF::notFound;
2245 };
2246
2247 RUN(testSimple());
2248
2249 RUN(testShuffleSimpleSwap());
2250 RUN(testShuffleSimpleShift());
2251 RUN(testShuffleLongShift());
2252 RUN(testShuffleLongShiftBackwards());
2253 RUN(testShuffleSimpleRotate());
2254 RUN(testShuffleSimpleBroadcast());
2255 RUN(testShuffleBroadcastAllRegs());
2256 RUN(testShuffleTreeShift());
2257 RUN(testShuffleTreeShiftBackward());
2258 RUN(testShuffleTreeShiftOtherBackward());
2259 RUN(testShuffleMultipleShifts());
2260 RUN(testShuffleRotateWithFringe());
2261 RUN(testShuffleRotateWithFringeInWeirdOrder());
2262 RUN(testShuffleRotateWithLongFringe());
2263 RUN(testShuffleMultipleRotates());
2264 RUN(testShuffleShiftAndRotate());
2265 RUN(testShuffleShiftAllRegs());
2266 RUN(testShuffleRotateAllRegs());
2267 RUN(testShuffleSimpleSwap64());
2268 RUN(testShuffleSimpleShift64());
2269 RUN(testShuffleSwapMixedWidth());
2270 RUN(testShuffleShiftMixedWidth());
2271 RUN(testShuffleShiftMemory());
2272 RUN(testShuffleShiftMemoryLong());
2273 RUN(testShuffleShiftMemoryAllRegs());
2274 RUN(testShuffleShiftMemoryAllRegs64());
2275 RUN(testShuffleShiftMemoryAllRegsMixedWidth());
2276 RUN(testShuffleRotateMemory());
2277 RUN(testShuffleRotateMemory64());
2278 RUN(testShuffleRotateMemoryMixedWidth());
2279 RUN(testShuffleRotateMemoryAllRegs64());
2280 RUN(testShuffleRotateMemoryAllRegsMixedWidth());
2281 RUN(testShuffleSwapDouble());
2282 RUN(testShuffleShiftDouble());
2283
2284#if CPU(X86) || CPU(X86_64)
2285 RUN(testX86VMULSD());
2286 RUN(testX86VMULSDDestRex());
2287 RUN(testX86VMULSDOp1DestRex());
2288 RUN(testX86VMULSDOp2DestRex());
2289 RUN(testX86VMULSDOpsDestRex());
2290
2291 RUN(testX86VMULSDAddr());
2292 RUN(testX86VMULSDAddrOpRexAddr());
2293 RUN(testX86VMULSDDestRexAddr());
2294 RUN(testX86VMULSDRegOpDestRexAddr());
2295 RUN(testX86VMULSDAddrOpDestRexAddr());
2296
2297 RUN(testX86VMULSDBaseNeedsRex());
2298 RUN(testX86VMULSDIndexNeedsRex());
2299 RUN(testX86VMULSDBaseIndexNeedRex());
2300#endif
2301
2302#if CPU(ARM64)
2303 RUN(testInvalidateCachedTempRegisters());
2304#endif
2305
2306 RUN(testArgumentRegPinned());
2307 RUN(testArgumentRegPinned2());
2308 RUN(testArgumentRegPinned3());
2309
2310 RUN(testLea32());
2311 RUN(testLea64());
2312
2313 RUN(testElideSimpleMove());
2314 RUN(testElideHandlesEarlyClobber());
2315 RUN(testElideMoveThenRealloc());
2316
2317 if (tasks.isEmpty())
2318 usage();
2319
2320 Lock lock;
2321
2322 Vector<Ref<Thread>> threads;
2323 for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) {
2324 threads.append(
2325 Thread::create(
2326 "testair thread",
2327 [&] () {
2328 for (;;) {
2329 RefPtr<SharedTask<void()>> task;
2330 {
2331 LockHolder locker(lock);
2332 if (tasks.isEmpty())
2333 return;
2334 task = tasks.takeFirst();
2335 }
2336
2337 task->run();
2338 }
2339 }));
2340 }
2341
2342 for (auto& thread : threads)
2343 thread->waitForCompletion();
2344 crashLock.lock();
2345 crashLock.unlock();
2346}
2347
2348} // anonymous namespace
2349
2350#else // ENABLE(B3_JIT)
2351
2352static void run(const char*)
2353{
2354 dataLog("B3 JIT is not enabled.\n");
2355}
2356
2357#endif // ENABLE(B3_JIT)
2358
2359int main(int argc, char** argv)
2360{
2361 const char* filter = nullptr;
2362 switch (argc) {
2363 case 1:
2364 break;
2365 case 2:
2366 filter = argv[1];
2367 break;
2368 default:
2369 usage();
2370 break;
2371 }
2372
2373 JSC::initializeThreading();
2374
2375 for (unsigned i = 0; i <= 2; ++i) {
2376 JSC::Options::defaultB3OptLevel() = i;
2377 run(filter);
2378 }
2379
2380 return 0;
2381}
2382
2383#if OS(WINDOWS)
2384extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
2385{
2386 return main(argc, const_cast<char**>(argv));
2387}
2388#endif
2389