| /* |
| * Copyright (C) 2015 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include "B3ArgumentRegValue.h" |
| #include "B3BasicBlockInlines.h" |
| #include "B3CCallValue.h" |
| #include "B3Compilation.h" |
| #include "B3Const32Value.h" |
| #include "B3ConstPtrValue.h" |
| #include "B3ControlValue.h" |
| #include "B3MemoryValue.h" |
| #include "B3Procedure.h" |
| #include "B3StackSlotValue.h" |
| #include "B3UpsilonValue.h" |
| #include "B3ValueInlines.h" |
| #include "CCallHelpers.h" |
| #include "InitializeThreading.h" |
| #include "JSCInlines.h" |
| #include "LinkBuffer.h" |
| #include "VM.h" |
| #include <wtf/Lock.h> |
| #include <wtf/NumberOfCores.h> |
| #include <wtf/Threading.h> |
| |
| // We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous. |
| static bool hiddenTruthBecauseNoReturnIsStupid() { return true; } |
| |
| static void usage() |
| { |
| dataLog("Usage: testb3 [<filter>]\n"); |
| if (hiddenTruthBecauseNoReturnIsStupid()) |
| exit(1); |
| } |
| |
| #if ENABLE(B3_JIT) |
| |
| using namespace JSC; |
| using namespace JSC::B3; |
| |
| namespace { |
| |
| // Nothing fancy for now; we just use the existing WTF assertion machinery. |
| #define CHECK(x) RELEASE_ASSERT(x) |
| |
| VM* vm; |
| |
| std::unique_ptr<Compilation> compile(Procedure& procedure) |
| { |
| return std::make_unique<Compilation>(*vm, procedure); |
| } |
| |
| template<typename T, typename... Arguments> |
| T invoke(const Compilation& code, Arguments... arguments) |
| { |
| T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(code.code().executableAddress()); |
| return function(arguments...); |
| } |
| |
| template<typename T, typename... Arguments> |
| T compileAndRun(Procedure& procedure, Arguments... arguments) |
| { |
| return invoke<T>(*compile(procedure), arguments...); |
| } |
| |
| void test42() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* const42 = root->appendNew<Const32Value>(proc, Origin(), 42); |
| root->appendNew<ControlValue>(proc, Return, Origin(), const42); |
| |
| CHECK(compileAndRun<int>(proc) == 42); |
| } |
| |
| void testLoad42() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int x = 42; |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), &x))); |
| |
| CHECK(compileAndRun<int>(proc) == 42); |
| } |
| |
| void testArg(int argument) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| |
| CHECK(compileAndRun<int>(proc, argument) == argument); |
| } |
| |
| void testReturnConst64(int64_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), value)); |
| |
| CHECK(compileAndRun<int64_t>(proc) == value); |
| } |
| |
| void testAddArgs(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == a + b); |
| } |
| |
| void testAddArgImm(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc, a) == a + b); |
| } |
| |
| void testAddImmArg(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int>(proc, b) == a + b); |
| } |
| |
| void testAddArgs32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == a + b); |
| } |
| |
| void testSubArgs(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == a - b); |
| } |
| |
| void testSubArgImm(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == a - b); |
| } |
| |
| void testSubImmArg(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int>(proc, b) == a - b); |
| } |
| |
| void testSubArgs32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == a - b); |
| } |
| |
| void testSubArgImm32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc, a) == a - b); |
| } |
| |
| void testSubImmArg32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int>(proc, b) == a - b); |
| } |
| |
| void testBitAndArgs(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a, b) == (a & b)); |
| } |
| |
| void testBitAndSameArg(int64_t a) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| argument, |
| argument)); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == a); |
| } |
| |
| void testBitAndImms(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc) == (a & b)); |
| } |
| |
| void testBitAndArgImm(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == (a & b)); |
| } |
| |
| void testBitAndImmArg(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int64_t>(proc, b) == (a & b)); |
| } |
| |
| void testBitAndBitAndArgImmImm(int64_t a, int64_t b, int64_t c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitAnd = root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| innerBitAnd, |
| root->appendNew<Const64Value>(proc, Origin(), c))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == ((a & b) & c)); |
| } |
| |
| void testBitAndImmBitAndArgImm(int64_t a, int64_t b, int64_t c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitAnd = root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), c)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| innerBitAnd)); |
| |
| CHECK(compileAndRun<int64_t>(proc, b) == (a & (b & c))); |
| } |
| |
| void testBitAndArgs32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == (a & b)); |
| } |
| |
| void testBitAndSameArg32(int a) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* argument = root->appendNew<Value>(proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| argument, |
| argument)); |
| |
| CHECK(compileAndRun<int>(proc, a) == a); |
| } |
| |
| void testBitAndImms32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc) == (a & b)); |
| } |
| |
| void testBitAndArgImm32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc, a) == (a & b)); |
| } |
| |
| void testBitAndImmArg32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int>(proc, b) == (a & b)); |
| } |
| |
| void testBitAndBitAndArgImmImm32(int a, int b, int c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitAnd = root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| innerBitAnd, |
| root->appendNew<Const32Value>(proc, Origin(), c))); |
| |
| CHECK(compileAndRun<int>(proc, a) == ((a & b) & c)); |
| } |
| |
| void testBitAndImmBitAndArgImm32(int a, int b, int c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitAnd = root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), c)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| innerBitAnd)); |
| |
| CHECK(compileAndRun<int>(proc, b) == (a & (b & c))); |
| } |
| |
| void testBitOrArgs(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a, b) == (a | b)); |
| } |
| |
| void testBitOrSameArg(int64_t a) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| argument, |
| argument)); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == a); |
| } |
| |
| void testBitOrImms(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc) == (a | b)); |
| } |
| |
| void testBitOrArgImm(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == (a | b)); |
| } |
| |
| void testBitOrImmArg(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int64_t>(proc, b) == (a | b)); |
| } |
| |
| void testBitOrBitOrArgImmImm(int64_t a, int64_t b, int64_t c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitOr = root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| innerBitOr, |
| root->appendNew<Const64Value>(proc, Origin(), c))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == ((a | b) | c)); |
| } |
| |
| void testBitOrImmBitOrArgImm(int64_t a, int64_t b, int64_t c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitOr = root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), c)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| innerBitOr)); |
| |
| CHECK(compileAndRun<int64_t>(proc, b) == (a | (b | c))); |
| } |
| |
| void testBitOrArgs32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == (a | b)); |
| } |
| |
| void testBitOrSameArg32(int a) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* argument = root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| argument, |
| argument)); |
| |
| CHECK(compileAndRun<int>(proc, a) == a); |
| } |
| |
| void testBitOrImms32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc) == (a | b)); |
| } |
| |
| void testBitOrArgImm32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc, a) == (a | b)); |
| } |
| |
| void testBitOrImmArg32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int>(proc, b) == (a | b)); |
| } |
| |
| void testBitOrBitOrArgImmImm32(int a, int b, int c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitOr = root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| innerBitOr, |
| root->appendNew<Const32Value>(proc, Origin(), c))); |
| |
| CHECK(compileAndRun<int>(proc, a) == ((a | b) | c)); |
| } |
| |
| void testBitOrImmBitOrArgImm32(int a, int b, int c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitOr = root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), c)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitOr, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| innerBitOr)); |
| |
| CHECK(compileAndRun<int>(proc, b) == (a | (b | c))); |
| } |
| |
| void testBitXorArgs(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a, b) == (a ^ b)); |
| } |
| |
| void testBitXorSameArg(int64_t a) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| argument, |
| argument)); |
| |
| CHECK(!compileAndRun<int64_t>(proc, a)); |
| } |
| |
| void testBitXorImms(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc) == (a ^ b)); |
| } |
| |
| void testBitXorArgImm(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == (a ^ b)); |
| } |
| |
| void testBitXorImmArg(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int64_t>(proc, b) == (a ^ b)); |
| } |
| |
| void testBitXorBitXorArgImmImm(int64_t a, int64_t b, int64_t c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitXor = root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), b)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| innerBitXor, |
| root->appendNew<Const64Value>(proc, Origin(), c))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == ((a ^ b) ^ c)); |
| } |
| |
| void testBitXorImmBitXorArgImm(int64_t a, int64_t b, int64_t c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitXor = root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const64Value>(proc, Origin(), c)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| innerBitXor)); |
| |
| CHECK(compileAndRun<int64_t>(proc, b) == (a ^ (b ^ c))); |
| } |
| |
| void testBitXorArgs32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == (a ^ b)); |
| } |
| |
| void testBitXorSameArg32(int a) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* argument = root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| argument, |
| argument)); |
| |
| CHECK(!compileAndRun<int>(proc, a)); |
| } |
| |
| void testBitXorImms32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc) == (a ^ b)); |
| } |
| |
| void testBitXorArgImm32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int>(proc, a) == (a ^ b)); |
| } |
| |
| void testBitXorImmArg32(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int>(proc, b) == (a ^ b)); |
| } |
| |
| void testBitXorBitXorArgImmImm32(int a, int b, int c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitXor = root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| innerBitXor, |
| root->appendNew<Const32Value>(proc, Origin(), c))); |
| |
| CHECK(compileAndRun<int>(proc, a) == ((a ^ b) ^ c)); |
| } |
| |
| void testBitXorImmBitXorArgImm32(int a, int b, int c) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* innerBitXor = root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), c)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, BitXor, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| innerBitXor)); |
| |
| CHECK(compileAndRun<int>(proc, b) == (a ^ (b ^ c))); |
| } |
| |
| void testShlArgs(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a, b) == (a << b)); |
| } |
| |
| void testShlImms(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc) == (a << b)); |
| } |
| |
| void testShlArgImm(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == (a << b)); |
| } |
| |
| void testShlArgs32(int32_t a, int32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int32_t>(proc, a, b) == (a << b)); |
| } |
| |
| void testShlImms32(int32_t a, int32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int32_t>(proc) == (a << b)); |
| } |
| |
| void testShlArgImm32(int32_t a, int32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int32_t>(proc, a) == (a << b)); |
| } |
| |
| void testSShrArgs(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, SShr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a, b) == (a >> b)); |
| } |
| |
| void testSShrImms(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, SShr, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc) == (a >> b)); |
| } |
| |
| void testSShrArgImm(int64_t a, int64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, SShr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int64_t>(proc, a) == (a >> b)); |
| } |
| |
| void testSShrArgs32(int32_t a, int32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, SShr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int32_t>(proc, a, b) == (a >> b)); |
| } |
| |
| void testSShrImms32(int32_t a, int32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, SShr, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int32_t>(proc) == (a >> b)); |
| } |
| |
| void testSShrArgImm32(int32_t a, int32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, SShr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<int32_t>(proc, a) == (a >> b)); |
| } |
| |
| void testZShrArgs(uint64_t a, uint64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ZShr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<uint64_t>(proc, a, b) == (a >> b)); |
| } |
| |
| void testZShrImms(uint64_t a, uint64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ZShr, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<uint64_t>(proc) == (a >> b)); |
| } |
| |
| void testZShrArgImm(uint64_t a, uint64_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ZShr, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<uint64_t>(proc, a) == (a >> b)); |
| } |
| |
| void testZShrArgs32(uint32_t a, uint32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ZShr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<uint32_t>(proc, a, b) == (a >> b)); |
| } |
| |
| void testZShrImms32(uint32_t a, uint32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ZShr, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), a), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<uint32_t>(proc) == (a >> b)); |
| } |
| |
| void testZShrArgImm32(uint32_t a, uint32_t b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ZShr, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), b))); |
| |
| CHECK(compileAndRun<uint32_t>(proc, a) == (a >> b)); |
| } |
| |
| void testStore(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int slot = 0xbaadbeef; |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc, value)); |
| CHECK(slot == value); |
| } |
| |
| void testStoreConstant(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int slot = 0xbaadbeef; |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), value), |
| root->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc)); |
| CHECK(slot == value); |
| } |
| |
| void testStoreConstantPtr(intptr_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| intptr_t slot; |
| if (is64Bit()) |
| slot = (static_cast<intptr_t>(0xbaadbeef) << 32) + static_cast<intptr_t>(0xbaadbeef); |
| else |
| slot = 0xbaadbeef; |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), value), |
| root->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc)); |
| CHECK(slot == value); |
| } |
| |
| void testTrunc(int64_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int>(proc, value) == static_cast<int>(value)); |
| } |
| |
| void testAdd1(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), 1))); |
| |
| CHECK(compileAndRun<int>(proc, value) == value + 1); |
| } |
| |
| void testAdd1Ptr(intptr_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ConstPtrValue>(proc, Origin(), 1))); |
| |
| CHECK(compileAndRun<intptr_t>(proc, value) == value + 1); |
| } |
| |
| void testNeg32(int32_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int32_t>(proc, value) == -value); |
| } |
| |
| void testNegPtr(intptr_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<intptr_t>(proc, value) == -value); |
| } |
| |
| void testStoreAddLoad(int amount) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int slot = 37; |
| ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), |
| root->appendNew<Const32Value>(proc, Origin(), amount)), |
| slotPtr); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc)); |
| CHECK(slot == 37 + amount); |
| } |
| |
| void testStoreSubLoad(int amount) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int32_t startValue = std::numeric_limits<int32_t>::min(); |
| int32_t slot = startValue; |
| ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), |
| slotPtr); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc, amount)); |
| CHECK(slot == startValue - amount); |
| } |
| |
| void testStoreAddLoadInterference(int amount) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int slot = 37; |
| ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); |
| ArgumentRegValue* otherSlotPtr = |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 666), |
| otherSlotPtr); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| load, root->appendNew<Const32Value>(proc, Origin(), amount)), |
| slotPtr); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc, &slot)); |
| CHECK(slot == 37 + amount); |
| } |
| |
| void testStoreAddAndLoad(int amount, int mask) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int slot = 37; |
| ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr), |
| root->appendNew<Const32Value>(proc, Origin(), amount)), |
| root->appendNew<Const32Value>(proc, Origin(), mask)), |
| slotPtr); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int>(proc)); |
| CHECK(slot == ((37 + amount) & mask)); |
| } |
| |
| void testStoreNegLoad32(int32_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| int32_t slot = value; |
| |
| ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); |
| |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)), |
| slotPtr); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int32_t>(proc)); |
| CHECK(slot == -value); |
| } |
| |
| void testStoreNegLoadPtr(intptr_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| intptr_t slot = value; |
| |
| ConstPtrValue* slotPtr = root->appendNew<ConstPtrValue>(proc, Origin(), &slot); |
| |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Sub, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0), |
| root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)), |
| slotPtr); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(!compileAndRun<int32_t>(proc)); |
| CHECK(slot == -value); |
| } |
| |
| void testAdd1Uncommuted(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 1), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int>(proc, value) == value + 1); |
| } |
| |
| void testLoadOffset() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int array[] = { 1, 2 }; |
| ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int)))); |
| |
| CHECK(compileAndRun<int>(proc) == array[0] + array[1]); |
| } |
| |
| void testLoadOffsetNotConstant() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int array[] = { 1, 2 }; |
| Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int)))); |
| |
| CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]); |
| } |
| |
| void testLoadOffsetUsingAdd() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int array[] = { 1, 2 }; |
| ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), arrayPtr, |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0))), |
| root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), arrayPtr, |
| root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int)))))); |
| |
| CHECK(compileAndRun<int>(proc) == array[0] + array[1]); |
| } |
| |
| void testLoadOffsetUsingAddInterference() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int array[] = { 1, 2 }; |
| ConstPtrValue* arrayPtr = root->appendNew<ConstPtrValue>(proc, Origin(), array); |
| ArgumentRegValue* otherArrayPtr = |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| Const32Value* theNumberOfTheBeast = root->appendNew<Const32Value>(proc, Origin(), 666); |
| MemoryValue* left = root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), arrayPtr, |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0))); |
| MemoryValue* right = root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), arrayPtr, |
| root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int)))); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0); |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int)); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), left, right)); |
| |
| CHECK(compileAndRun<int>(proc, &array[0]) == 1 + 2); |
| CHECK(array[0] == 666); |
| CHECK(array[1] == 666); |
| } |
| |
| void testLoadOffsetUsingAddNotConstant() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| int array[] = { 1, 2 }; |
| Value* arrayPtr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), arrayPtr, |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0))), |
| root->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), arrayPtr, |
| root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int)))))); |
| |
| CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]); |
| } |
| |
| void testFramePointer() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>(proc, FramePointer, Origin())); |
| |
| void* fp = compileAndRun<void*>(proc); |
| CHECK(fp < &proc); |
| CHECK(fp >= bitwise_cast<char*>(&proc) - 10000); |
| } |
| |
| void testStackSlot() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<StackSlotValue>(proc, Origin(), 1, StackSlotKind::Anonymous)); |
| |
| void* stackSlot = compileAndRun<void*>(proc); |
| CHECK(stackSlot < &proc); |
| CHECK(stackSlot >= bitwise_cast<char*>(&proc) - 10000); |
| } |
| |
| void testLoadFromFramePointer() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, Load, pointerType(), Origin(), |
| root->appendNew<Value>(proc, FramePointer, Origin()))); |
| |
| void* fp = compileAndRun<void*>(proc); |
| void* myFP = __builtin_frame_address(0); |
| CHECK(fp <= myFP); |
| CHECK(fp >= bitwise_cast<char*>(myFP) - 10000); |
| } |
| |
| void testStoreLoadStackSlot(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| StackSlotValue* stack = root->appendNew<StackSlotValue>( |
| proc, Origin(), sizeof(int), StackSlotKind::Anonymous); |
| |
| root->appendNew<MemoryValue>( |
| proc, Store, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| stack); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), stack)); |
| |
| CHECK(compileAndRun<int>(proc, value) == value); |
| } |
| |
| template<typename T> |
| int32_t modelLoad(int32_t value) |
| { |
| union { |
| int32_t original; |
| T loaded; |
| } u; |
| |
| u.original = value; |
| if (std::is_signed<T>::value) |
| return static_cast<int32_t>(u.loaded); |
| return static_cast<int32_t>(static_cast<uint32_t>(u.loaded)); |
| } |
| |
| template<typename T> |
| void testLoad(B3::Opcode opcode, int32_t value) |
| { |
| // Simple load from an absolute address. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, opcode, Int32, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), &value))); |
| |
| CHECK(compileAndRun<int32_t>(proc) == modelLoad<T>(value)); |
| } |
| |
| // Simple load from an address in a register. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, opcode, Int32, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))); |
| |
| CHECK(compileAndRun<int32_t>(proc, &value) == modelLoad<T>(value)); |
| } |
| |
| // Simple load from an address in a register, at an offset. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, opcode, Int32, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| sizeof(int32_t))); |
| |
| CHECK(compileAndRun<int32_t>(proc, &value - 1) == modelLoad<T>(value)); |
| } |
| |
| // Load from a simple base-index with various scales. |
| for (unsigned logScale = 0; logScale <= 3; ++logScale) { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, opcode, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), |
| root->appendNew<Const32Value>(proc, Origin(), logScale))))); |
| |
| CHECK(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value)); |
| } |
| |
| // Load from a simple base-index with various scales, but commuted. |
| for (unsigned logScale = 0; logScale <= 3; ++logScale) { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<MemoryValue>( |
| proc, opcode, Int32, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<Value>( |
| proc, Shl, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1), |
| root->appendNew<Const32Value>(proc, Origin(), logScale)), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)))); |
| |
| CHECK(compileAndRun<int32_t>(proc, &value - 2, (sizeof(int32_t) * 2) >> logScale) == modelLoad<T>(value)); |
| } |
| } |
| |
| void testSpillGP() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| Vector<Value*> sources; |
| sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| sources.append(root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); |
| |
| for (unsigned i = 0; i < 30; ++i) { |
| sources.append( |
| root->appendNew<Value>(proc, Add, Origin(), sources[sources.size() - 1], sources[sources.size() - 2]) |
| ); |
| } |
| |
| Value* total = root->appendNew<Const64Value>(proc, Origin(), 0); |
| for (Value* value : sources) |
| total = root->appendNew<Value>(proc, Add, Origin(), total, value); |
| |
| root->appendNew<ControlValue>(proc, Return, Origin(), total); |
| compileAndRun<int>(proc, 1, 2); |
| } |
| |
| void testBranch() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchPtr() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, static_cast<intptr_t>(42)) == 1); |
| CHECK(invoke<int>(*code, static_cast<intptr_t>(0)) == 0); |
| } |
| |
| void testDiamond() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| BasicBlock* done = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>( |
| proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); |
| |
| UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>( |
| proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); |
| |
| Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin()); |
| thenResult->setPhi(phi); |
| elseResult->setPhi(phi); |
| done->appendNew<ControlValue>(proc, Return, Origin(), phi); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchNotEqual() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, NotEqual, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchNotEqualCommute() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, NotEqual, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchNotEqualNotEqual() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, NotEqual, Origin(), |
| root->appendNew<Value>( |
| proc, NotEqual, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchEqual() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchEqualEqual() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchEqualCommute() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), 0), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchEqualEqual1() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Const32Value>(proc, Origin(), 0)), |
| root->appendNew<Const32Value>(proc, Origin(), 1)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| auto code = compile(proc); |
| CHECK(invoke<int>(*code, 42) == 1); |
| CHECK(invoke<int>(*code, 0) == 0); |
| } |
| |
| void testBranchFold(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), value), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(compileAndRun<int>(proc) == !!value); |
| } |
| |
| void testDiamondFold(int value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| BasicBlock* done = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), value), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>( |
| proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); |
| |
| UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>( |
| proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done)); |
| |
| Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin()); |
| thenResult->setPhi(phi); |
| elseResult->setPhi(phi); |
| done->appendNew<ControlValue>(proc, Return, Origin(), phi); |
| |
| CHECK(compileAndRun<int>(proc) == !!value); |
| } |
| |
| void testBranchNotEqualFoldPtr(intptr_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, NotEqual, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), value), |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(compileAndRun<int>(proc) == !!value); |
| } |
| |
| void testBranchEqualFoldPtr(intptr_t value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, Equal, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), value), |
| root->appendNew<ConstPtrValue>(proc, Origin(), 0)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| thenCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| thenCase->appendNew<Const32Value>(proc, Origin(), 1)); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(compileAndRun<int>(proc) == !value); |
| } |
| |
| void testComplex(unsigned numVars, unsigned numConstructs) |
| { |
| double before = monotonicallyIncreasingTimeMS(); |
| |
| Procedure proc; |
| BasicBlock* current = proc.addBlock(); |
| |
| Const32Value* one = current->appendNew<Const32Value>(proc, Origin(), 1); |
| |
| Vector<int32_t> varSlots; |
| for (unsigned i = numVars; i--;) |
| varSlots.append(i); |
| |
| Vector<Value*> vars; |
| for (int32_t& varSlot : varSlots) { |
| Value* varSlotPtr = current->appendNew<ConstPtrValue>(proc, Origin(), &varSlot); |
| vars.append(current->appendNew<MemoryValue>(proc, Load, Int32, Origin(), varSlotPtr)); |
| } |
| |
| for (unsigned i = 0; i < numConstructs; ++i) { |
| if (i & 1) { |
| // Control flow diamond. |
| unsigned predicateVarIndex = (i >> 1) % numVars; |
| unsigned thenIncVarIndex = ((i >> 1) + 1) % numVars; |
| unsigned elseIncVarIndex = ((i >> 1) + 2) % numVars; |
| |
| BasicBlock* thenBlock = proc.addBlock(); |
| BasicBlock* elseBlock = proc.addBlock(); |
| BasicBlock* continuation = proc.addBlock(); |
| |
| current->appendNew<ControlValue>( |
| proc, Branch, Origin(), vars[predicateVarIndex], |
| FrequentedBlock(thenBlock), FrequentedBlock(elseBlock)); |
| |
| UpsilonValue* thenThenResult = thenBlock->appendNew<UpsilonValue>( |
| proc, Origin(), |
| thenBlock->appendNew<Value>(proc, Add, Origin(), vars[thenIncVarIndex], one)); |
| UpsilonValue* thenElseResult = thenBlock->appendNew<UpsilonValue>( |
| proc, Origin(), vars[elseIncVarIndex]); |
| thenBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); |
| |
| UpsilonValue* elseElseResult = elseBlock->appendNew<UpsilonValue>( |
| proc, Origin(), |
| elseBlock->appendNew<Value>(proc, Add, Origin(), vars[elseIncVarIndex], one)); |
| UpsilonValue* elseThenResult = elseBlock->appendNew<UpsilonValue>( |
| proc, Origin(), vars[thenIncVarIndex]); |
| elseBlock->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); |
| |
| Value* thenPhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin()); |
| thenThenResult->setPhi(thenPhi); |
| elseThenResult->setPhi(thenPhi); |
| vars[thenIncVarIndex] = thenPhi; |
| |
| Value* elsePhi = continuation->appendNew<Value>(proc, Phi, Int32, Origin()); |
| thenElseResult->setPhi(elsePhi); |
| elseElseResult->setPhi(elsePhi); |
| vars[elseIncVarIndex] = thenPhi; |
| |
| current = continuation; |
| } else { |
| // Loop. |
| |
| BasicBlock* loopEntry = proc.addBlock(); |
| BasicBlock* loopReentry = proc.addBlock(); |
| BasicBlock* loopBody = proc.addBlock(); |
| BasicBlock* loopExit = proc.addBlock(); |
| BasicBlock* loopSkip = proc.addBlock(); |
| BasicBlock* continuation = proc.addBlock(); |
| |
| Value* startIndex = vars[(i >> 1) % numVars]; |
| Value* startSum = current->appendNew<Const32Value>(proc, Origin(), 0); |
| current->appendNew<ControlValue>( |
| proc, Branch, Origin(), startIndex, |
| FrequentedBlock(loopEntry), FrequentedBlock(loopSkip)); |
| |
| UpsilonValue* startIndexForBody = loopEntry->appendNew<UpsilonValue>( |
| proc, Origin(), startIndex); |
| UpsilonValue* startSumForBody = loopEntry->appendNew<UpsilonValue>( |
| proc, Origin(), startSum); |
| loopEntry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody)); |
| |
| Value* bodyIndex = loopBody->appendNew<Value>(proc, Phi, Int32, Origin()); |
| startIndexForBody->setPhi(bodyIndex); |
| Value* bodySum = loopBody->appendNew<Value>(proc, Phi, Int32, Origin()); |
| startSumForBody->setPhi(bodySum); |
| Value* newBodyIndex = loopBody->appendNew<Value>(proc, Sub, Origin(), bodyIndex, one); |
| Value* newBodySum = loopBody->appendNew<Value>( |
| proc, Add, Origin(), |
| bodySum, |
| loopBody->appendNew<MemoryValue>( |
| proc, Load, Int32, Origin(), |
| loopBody->appendNew<Value>( |
| proc, Add, Origin(), |
| loopBody->appendNew<ConstPtrValue>(proc, Origin(), varSlots.data()), |
| loopBody->appendNew<Value>( |
| proc, Shl, Origin(), |
| loopBody->appendNew<Value>( |
| proc, ZExt32, Origin(), |
| loopBody->appendNew<Value>( |
| proc, BitAnd, Origin(), |
| newBodyIndex, |
| loopBody->appendNew<Const32Value>( |
| proc, Origin(), numVars - 1))), |
| loopBody->appendNew<Const32Value>(proc, Origin(), 2))))); |
| loopBody->appendNew<ControlValue>( |
| proc, Branch, Origin(), newBodyIndex, |
| FrequentedBlock(loopReentry), FrequentedBlock(loopExit)); |
| |
| loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodyIndex, bodyIndex); |
| loopReentry->appendNew<UpsilonValue>(proc, Origin(), newBodySum, bodySum); |
| loopReentry->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(loopBody)); |
| |
| UpsilonValue* exitSum = loopExit->appendNew<UpsilonValue>(proc, Origin(), newBodySum); |
| loopExit->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); |
| |
| UpsilonValue* skipSum = loopSkip->appendNew<UpsilonValue>(proc, Origin(), startSum); |
| loopSkip->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(continuation)); |
| |
| Value* finalSum = continuation->appendNew<Value>(proc, Phi, Int32, Origin()); |
| exitSum->setPhi(finalSum); |
| skipSum->setPhi(finalSum); |
| |
| current = continuation; |
| vars[((i >> 1) + 1) % numVars] = finalSum; |
| } |
| } |
| |
| current->appendNew<ControlValue>(proc, Return, Origin(), vars[0]); |
| |
| compile(proc); |
| |
| double after = monotonicallyIncreasingTimeMS(); |
| dataLog(toCString(" That took ", after - before, " ms.\n")); |
| } |
| |
| void testSimplePatchpoint() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); |
| PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin()); |
| patchpoint->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); |
| patchpoint->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); |
| patchpoint->setGenerator( |
| [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
| CHECK(params.reps.size() == 3); |
| CHECK(params.reps[0].isGPR()); |
| CHECK(params.reps[1].isGPR()); |
| CHECK(params.reps[2].isGPR()); |
| jit.move(params.reps[1].gpr(), params.reps[0].gpr()); |
| jit.add32(params.reps[2].gpr(), params.reps[0].gpr()); |
| }); |
| root->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); |
| |
| CHECK(compileAndRun<int>(proc, 1, 2) == 3); |
| } |
| |
| void testSimpleCheck() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| CheckValue* check = root->appendNew<CheckValue>(proc, Check, Origin(), arg); |
| check->setGenerator( |
| [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
| CHECK(params.reps.size() == 1); |
| CHECK(params.reps[0].isConstant()); |
| CHECK(params.reps[0].value() == 1); |
| |
| // This should always work because a function this simple should never have callee |
| // saves. |
| jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); |
| jit.emitFunctionEpilogue(); |
| jit.ret(); |
| }); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| |
| CHECK(invoke<int>(*code, 0) == 0); |
| CHECK(invoke<int>(*code, 1) == 42); |
| } |
| |
| void testCheckLessThan() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* arg = root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| CheckValue* check = root->appendNew<CheckValue>( |
| proc, Check, Origin(), |
| root->appendNew<Value>( |
| proc, LessThan, Origin(), arg, |
| root->appendNew<Const32Value>(proc, Origin(), 42))); |
| check->setGenerator( |
| [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
| CHECK(params.reps.size() == 1); |
| CHECK(params.reps[0].isConstant()); |
| CHECK(params.reps[0].value() == 1); |
| |
| // This should always work because a function this simple should never have callee |
| // saves. |
| jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); |
| jit.emitFunctionEpilogue(); |
| jit.ret(); |
| }); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| |
| CHECK(invoke<int>(*code, 42) == 0); |
| CHECK(invoke<int>(*code, 1000) == 0); |
| CHECK(invoke<int>(*code, 41) == 42); |
| CHECK(invoke<int>(*code, 0) == 42); |
| CHECK(invoke<int>(*code, -1) == 42); |
| } |
| |
| void testCheckMegaCombo() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); |
| Value* index = root->appendNew<Value>( |
| proc, ZExt32, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| Value* ptr = root->appendNew<Value>( |
| proc, Add, Origin(), base, |
| root->appendNew<Value>( |
| proc, Shl, Origin(), index, |
| root->appendNew<Const32Value>(proc, Origin(), 1))); |
| |
| CheckValue* check = root->appendNew<CheckValue>( |
| proc, Check, Origin(), |
| root->appendNew<Value>( |
| proc, LessThan, Origin(), |
| root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr), |
| root->appendNew<Const32Value>(proc, Origin(), 42))); |
| check->setGenerator( |
| [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
| CHECK(params.reps.size() == 1); |
| CHECK(params.reps[0].isConstant()); |
| CHECK(params.reps[0].value() == 1); |
| |
| // This should always work because a function this simple should never have callee |
| // saves. |
| jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); |
| jit.emitFunctionEpilogue(); |
| jit.ret(); |
| }); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| auto code = compile(proc); |
| |
| int8_t value; |
| value = 42; |
| CHECK(invoke<int>(*code, &value - 2, 1) == 0); |
| value = 127; |
| CHECK(invoke<int>(*code, &value - 2, 1) == 0); |
| value = 41; |
| CHECK(invoke<int>(*code, &value - 2, 1) == 42); |
| value = 0; |
| CHECK(invoke<int>(*code, &value - 2, 1) == 42); |
| value = -1; |
| CHECK(invoke<int>(*code, &value - 2, 1) == 42); |
| } |
| |
| template<typename LeftFunctor, typename RightFunctor> |
| void genericTestCompare( |
| B3::Opcode opcode, const LeftFunctor& leftFunctor, const RightFunctor& rightFunctor, |
| int left, int right, int result) |
| { |
| // Using a compare. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, NotEqual, Origin(), |
| root->appendNew<Value>( |
| proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)), |
| root->appendNew<Const32Value>(proc, Origin(), 0))); |
| |
| CHECK(compileAndRun<int>(proc, left, right) == result); |
| } |
| |
| // Using a branch. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| BasicBlock* thenCase = proc.addBlock(); |
| BasicBlock* elseCase = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Branch, Origin(), |
| root->appendNew<Value>( |
| proc, opcode, Origin(), leftFunctor(root, proc), rightFunctor(root, proc)), |
| FrequentedBlock(thenCase), FrequentedBlock(elseCase)); |
| |
| // We use a patchpoint on the then case to ensure that this doesn't get if-converted. |
| PatchpointValue* patchpoint = thenCase->appendNew<PatchpointValue>(proc, Int32, Origin()); |
| patchpoint->setGenerator( |
| [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
| CHECK(params.reps.size() == 1); |
| CHECK(params.reps[0].isGPR()); |
| jit.move(CCallHelpers::TrustedImm32(1), params.reps[0].gpr()); |
| }); |
| thenCase->appendNew<ControlValue>(proc, Return, Origin(), patchpoint); |
| |
| elseCase->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| elseCase->appendNew<Const32Value>(proc, Origin(), 0)); |
| |
| CHECK(compileAndRun<int>(proc, left, right) == result); |
| } |
| } |
| |
| int modelCompare(B3::Opcode opcode, int left, int right) |
| { |
| switch (opcode) { |
| case Equal: |
| return left == right; |
| case NotEqual: |
| return left != right; |
| case LessThan: |
| return left < right; |
| case GreaterThan: |
| return left > right; |
| case LessEqual: |
| return left <= right; |
| case GreaterEqual: |
| return left >= right; |
| case Above: |
| return static_cast<unsigned>(left) > static_cast<unsigned>(right); |
| case Below: |
| return static_cast<unsigned>(left) < static_cast<unsigned>(right); |
| case AboveEqual: |
| return static_cast<unsigned>(left) >= static_cast<unsigned>(right); |
| case BelowEqual: |
| return static_cast<unsigned>(left) <= static_cast<unsigned>(right); |
| case BitAnd: |
| return !!(left & right); |
| default: |
| RELEASE_ASSERT_NOT_REACHED(); |
| return 0; |
| } |
| } |
| |
| template<typename T> |
| void testCompareLoad(B3::Opcode opcode, B3::Opcode loadOpcode, int left, int right) |
| { |
| int result = modelCompare(opcode, modelLoad<T>(left), right); |
| |
| // Test addr-to-tmp |
| int slot = left; |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<MemoryValue>( |
| proc, loadOpcode, Int32, Origin(), |
| block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Value>( |
| proc, Trunc, Origin(), |
| block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); |
| }, |
| left, right, result); |
| |
| // Test addr-to-imm |
| slot = left; |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<MemoryValue>( |
| proc, loadOpcode, Int32, Origin(), |
| block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Const32Value>(proc, Origin(), right); |
| }, |
| left, right, result); |
| |
| result = modelCompare(opcode, left, modelLoad<T>(right)); |
| |
| // Test tmp-to-addr |
| slot = right; |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Value>( |
| proc, Trunc, Origin(), |
| block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<MemoryValue>( |
| proc, loadOpcode, Int32, Origin(), |
| block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| }, |
| left, right, result); |
| |
| // Test imm-to-addr |
| slot = right; |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Const32Value>(proc, Origin(), left); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<MemoryValue>( |
| proc, loadOpcode, Int32, Origin(), |
| block->appendNew<ConstPtrValue>(proc, Origin(), &slot)); |
| }, |
| left, right, result); |
| } |
| |
| void testCompareImpl(B3::Opcode opcode, int left, int right) |
| { |
| int result = modelCompare(opcode, left, right); |
| |
| // Test tmp-to-tmp. |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Value>( |
| proc, Trunc, Origin(), |
| block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Value>( |
| proc, Trunc, Origin(), |
| block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); |
| }, |
| left, right, result); |
| |
| // Test imm-to-tmp. |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Const32Value>(proc, Origin(), left); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Value>( |
| proc, Trunc, Origin(), |
| block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); |
| }, |
| left, right, result); |
| |
| // Test tmp-to-imm. |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Value>( |
| proc, Trunc, Origin(), |
| block->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Const32Value>(proc, Origin(), right); |
| }, |
| left, right, result); |
| |
| // Test imm-to-imm. |
| genericTestCompare( |
| opcode, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Const32Value>(proc, Origin(), left); |
| }, |
| [&] (BasicBlock* block, Procedure& proc) { |
| return block->appendNew<Const32Value>(proc, Origin(), right); |
| }, |
| left, right, result); |
| |
| testCompareLoad<int32_t>(opcode, Load, left, right); |
| testCompareLoad<int8_t>(opcode, Load8S, left, right); |
| testCompareLoad<uint8_t>(opcode, Load8Z, left, right); |
| testCompareLoad<int16_t>(opcode, Load16S, left, right); |
| testCompareLoad<uint16_t>(opcode, Load16Z, left, right); |
| } |
| |
| void testCompare(B3::Opcode opcode, int left, int right) |
| { |
| auto variants = [&] (int left, int right) { |
| testCompareImpl(opcode, left, right); |
| testCompareImpl(opcode, left, right + 1); |
| testCompareImpl(opcode, left, right - 1); |
| |
| auto multipliedTests = [&] (int factor) { |
| testCompareImpl(opcode, left * factor, right); |
| testCompareImpl(opcode, left * factor, right + 1); |
| testCompareImpl(opcode, left * factor, right - 1); |
| |
| testCompareImpl(opcode, left, right * factor); |
| testCompareImpl(opcode, left, (right + 1) * factor); |
| testCompareImpl(opcode, left, (right - 1) * factor); |
| |
| testCompareImpl(opcode, left * factor, right * factor); |
| testCompareImpl(opcode, left * factor, (right + 1) * factor); |
| testCompareImpl(opcode, left * factor, (right - 1) * factor); |
| }; |
| |
| multipliedTests(10); |
| multipliedTests(100); |
| multipliedTests(1000); |
| multipliedTests(100000); |
| }; |
| |
| variants(left, right); |
| variants(-left, right); |
| variants(left, -right); |
| variants(-left, -right); |
| } |
| |
| int simpleFunction(int a, int b) |
| { |
| return a + b; |
| } |
| |
| void testCallSimple(int a, int b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<CCallValue>( |
| proc, Int32, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunction)), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int>(proc, a, b) == a + b); |
| } |
| |
| int functionWithHellaArguments(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int x, int y, int z) |
| { |
| return (a << 0) + (b << 1) + (c << 2) + (d << 3) + (e << 4) + (f << 5) + (g << 6) + (h << 7) + (i << 8) + (j << 9) + (k << 10) + (l << 11) + (m << 12) + (n << 13) + (o << 14) + (p << 15) + (q << 16) + (r << 17) + (s << 18) + (t << 19) + (u << 20) + (v << 21) + (w << 22) + (x << 23) + (y << 24) + (z << 25); |
| } |
| |
| void testCallFunctionWithHellaArguments() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| Vector<Value*> args; |
| for (unsigned i = 0; i < 26; ++i) |
| args.append(root->appendNew<Const32Value>(proc, Origin(), i + 1)); |
| |
| CCallValue* call = root->appendNew<CCallValue>( |
| proc, Int32, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaArguments))); |
| call->children().appendVector(args); |
| |
| root->appendNew<ControlValue>(proc, Return, Origin(), call); |
| |
| CHECK(compileAndRun<int>(proc) == functionWithHellaArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)); |
| } |
| |
| void testReturnDouble(double value) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<ConstDoubleValue>(proc, Origin(), value)); |
| |
| CHECK(isIdentical(compileAndRun<double>(proc), value)); |
| } |
| |
| double simpleFunctionDouble(double a, double b) |
| { |
| return a + b; |
| } |
| |
| void testCallSimpleDouble(double a, double b) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<CCallValue>( |
| proc, Double, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(simpleFunctionDouble)), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1))); |
| |
| CHECK(compileAndRun<double>(proc, a, b) == a + b); |
| } |
| |
| double functionWithHellaDoubleArguments(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, double k, double l, double m, double n, double o, double p, double q, double r, double s, double t, double u, double v, double w, double x, double y, double z) |
| { |
| return a * pow(2, 0) + b * pow(2, 1) + c * pow(2, 2) + d * pow(2, 3) + e * pow(2, 4) + f * pow(2, 5) + g * pow(2, 6) + h * pow(2, 7) + i * pow(2, 8) + j * pow(2, 9) + k * pow(2, 10) + l * pow(2, 11) + m * pow(2, 12) + n * pow(2, 13) + o * pow(2, 14) + p * pow(2, 15) + q * pow(2, 16) + r * pow(2, 17) + s * pow(2, 18) + t * pow(2, 19) + u * pow(2, 20) + v * pow(2, 21) + w * pow(2, 22) + x * pow(2, 23) + y * pow(2, 24) + z * pow(2, 25); |
| } |
| |
| void testCallFunctionWithHellaDoubleArguments() |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| Vector<Value*> args; |
| for (unsigned i = 0; i < 26; ++i) |
| args.append(root->appendNew<ConstDoubleValue>(proc, Origin(), i + 1)); |
| |
| CCallValue* call = root->appendNew<CCallValue>( |
| proc, Double, Origin(), |
| root->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<void*>(functionWithHellaDoubleArguments))); |
| call->children().appendVector(args); |
| |
| root->appendNew<ControlValue>(proc, Return, Origin(), call); |
| |
| CHECK(compileAndRun<double>(proc) == functionWithHellaDoubleArguments(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)); |
| } |
| |
| void testChillDiv(int num, int den, int res) |
| { |
| // Test non-constant. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ChillDiv, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)))); |
| |
| CHECK(compileAndRun<int>(proc, num, den) == res); |
| } |
| |
| // Test constant. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ChillDiv, Origin(), |
| root->appendNew<Const32Value>(proc, Origin(), num), |
| root->appendNew<Const32Value>(proc, Origin(), den))); |
| |
| CHECK(compileAndRun<int>(proc) == res); |
| } |
| } |
| |
| void testChillDivTwice(int num1, int den1, int num2, int den2, int res) |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, Add, Origin(), |
| root->appendNew<Value>( |
| proc, ChillDiv, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))), |
| root->appendNew<Value>( |
| proc, ChillDiv, Origin(), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)), |
| root->appendNew<Value>( |
| proc, Trunc, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3))))); |
| |
| CHECK(compileAndRun<int>(proc, num1, den1, num2, den2) == res); |
| } |
| |
| void testChillDiv64(int64_t num, int64_t den, int64_t res) |
| { |
| if (!is64Bit()) |
| return; |
| |
| // Test non-constant. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ChillDiv, Origin(), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0), |
| root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))); |
| |
| CHECK(compileAndRun<int64_t>(proc, num, den) == res); |
| } |
| |
| // Test constant. |
| { |
| Procedure proc; |
| BasicBlock* root = proc.addBlock(); |
| |
| root->appendNew<ControlValue>( |
| proc, Return, Origin(), |
| root->appendNew<Value>( |
| proc, ChillDiv, Origin(), |
| root->appendNew<Const64Value>(proc, Origin(), num), |
| root->appendNew<Const64Value>(proc, Origin(), den))); |
| |
| CHECK(compileAndRun<int64_t>(proc) == res); |
| } |
| } |
| |
| #define RUN(test) do { \ |
| if (!shouldRun(#test)) \ |
| break; \ |
| tasks.append( \ |
| createSharedTask<void()>( \ |
| [&] () { \ |
| dataLog(#test "...\n"); \ |
| test; \ |
| dataLog(#test ": OK!\n"); \ |
| })); \ |
| } while (false); |
| |
| void run(const char* filter) |
| { |
| JSC::initializeThreading(); |
| vm = &VM::create(LargeHeap).leakRef(); |
| |
| Deque<RefPtr<SharedTask<void()>>> tasks; |
| |
| auto shouldRun = [&] (const char* testName) -> bool { |
| return !filter || !!strcasestr(testName, filter); |
| }; |
| |
| RUN(test42()); |
| RUN(testLoad42()); |
| RUN(testArg(43)); |
| RUN(testReturnConst64(5)); |
| RUN(testReturnConst64(-42)); |
| |
| RUN(testAddArgs(1, 1)); |
| RUN(testAddArgs(1, 2)); |
| RUN(testAddArgImm(1, 2)); |
| RUN(testAddArgImm(0, 2)); |
| RUN(testAddArgImm(1, 0)); |
| RUN(testAddImmArg(1, 2)); |
| RUN(testAddImmArg(0, 2)); |
| RUN(testAddImmArg(1, 0)); |
| RUN(testAddArgs32(1, 1)); |
| RUN(testAddArgs32(1, 2)); |
| |
| RUN(testSubArgs(1, 1)); |
| RUN(testSubArgs(1, 2)); |
| RUN(testSubArgs(13, -42)); |
| RUN(testSubArgs(-13, 42)); |
| RUN(testSubArgImm(1, 1)); |
| RUN(testSubArgImm(1, 2)); |
| RUN(testSubArgImm(13, -42)); |
| RUN(testSubArgImm(-13, 42)); |
| RUN(testSubArgImm(42, 0)); |
| RUN(testSubImmArg(1, 1)); |
| RUN(testSubImmArg(1, 2)); |
| RUN(testSubImmArg(13, -42)); |
| RUN(testSubImmArg(-13, 42)); |
| |
| RUN(testSubArgs32(1, 1)); |
| RUN(testSubArgs32(1, 2)); |
| RUN(testSubArgs32(13, -42)); |
| RUN(testSubArgs32(-13, 42)); |
| RUN(testSubArgImm32(1, 1)); |
| RUN(testSubArgImm32(1, 2)); |
| RUN(testSubArgImm32(13, -42)); |
| RUN(testSubArgImm32(-13, 42)); |
| RUN(testSubImmArg32(1, 1)); |
| RUN(testSubImmArg32(1, 2)); |
| RUN(testSubImmArg32(13, -42)); |
| RUN(testSubImmArg32(-13, 42)); |
| |
| RUN(testBitAndArgs(43, 43)); |
| RUN(testBitAndArgs(43, 0)); |
| RUN(testBitAndArgs(10, 3)); |
| RUN(testBitAndArgs(42, 0xffffffffffffffff)); |
| RUN(testBitAndSameArg(43)); |
| RUN(testBitAndSameArg(0)); |
| RUN(testBitAndSameArg(3)); |
| RUN(testBitAndSameArg(0xffffffffffffffff)); |
| RUN(testBitAndImms(43, 43)); |
| RUN(testBitAndImms(43, 0)); |
| RUN(testBitAndImms(10, 3)); |
| RUN(testBitAndImms(42, 0xffffffffffffffff)); |
| RUN(testBitAndArgImm(43, 43)); |
| RUN(testBitAndArgImm(43, 0)); |
| RUN(testBitAndArgImm(10, 3)); |
| RUN(testBitAndArgImm(42, 0xffffffffffffffff)); |
| RUN(testBitAndImmArg(43, 43)); |
| RUN(testBitAndImmArg(43, 0)); |
| RUN(testBitAndImmArg(10, 3)); |
| RUN(testBitAndImmArg(42, 0xffffffffffffffff)); |
| RUN(testBitAndBitAndArgImmImm(2, 7, 3)); |
| RUN(testBitAndBitAndArgImmImm(1, 6, 6)); |
| RUN(testBitAndBitAndArgImmImm(0xffff, 24, 7)); |
| RUN(testBitAndImmBitAndArgImm(7, 2, 3)); |
| RUN(testBitAndImmBitAndArgImm(6, 1, 6)); |
| RUN(testBitAndImmBitAndArgImm(24, 0xffff, 7)); |
| RUN(testBitAndArgs32(43, 43)); |
| RUN(testBitAndArgs32(43, 0)); |
| RUN(testBitAndArgs32(10, 3)); |
| RUN(testBitAndArgs32(42, 0xffffffff)); |
| RUN(testBitAndSameArg32(43)); |
| RUN(testBitAndSameArg32(0)); |
| RUN(testBitAndSameArg32(3)); |
| RUN(testBitAndSameArg32(0xffffffff)); |
| RUN(testBitAndImms32(43, 43)); |
| RUN(testBitAndImms32(43, 0)); |
| RUN(testBitAndImms32(10, 3)); |
| RUN(testBitAndImms32(42, 0xffffffff)); |
| RUN(testBitAndArgImm32(43, 43)); |
| RUN(testBitAndArgImm32(43, 0)); |
| RUN(testBitAndArgImm32(10, 3)); |
| RUN(testBitAndArgImm32(42, 0xffffffff)); |
| RUN(testBitAndImmArg32(43, 43)); |
| RUN(testBitAndImmArg32(43, 0)); |
| RUN(testBitAndImmArg32(10, 3)); |
| RUN(testBitAndImmArg32(42, 0xffffffff)); |
| RUN(testBitAndBitAndArgImmImm32(2, 7, 3)); |
| RUN(testBitAndBitAndArgImmImm32(1, 6, 6)); |
| RUN(testBitAndBitAndArgImmImm32(0xffff, 24, 7)); |
| RUN(testBitAndImmBitAndArgImm32(7, 2, 3)); |
| RUN(testBitAndImmBitAndArgImm32(6, 1, 6)); |
| RUN(testBitAndImmBitAndArgImm32(24, 0xffff, 7)); |
| |
| RUN(testBitOrArgs(43, 43)); |
| RUN(testBitOrArgs(43, 0)); |
| RUN(testBitOrArgs(10, 3)); |
| RUN(testBitOrArgs(42, 0xffffffffffffffff)); |
| RUN(testBitOrSameArg(43)); |
| RUN(testBitOrSameArg(0)); |
| RUN(testBitOrSameArg(3)); |
| RUN(testBitOrSameArg(0xffffffffffffffff)); |
| RUN(testBitOrImms(43, 43)); |
| RUN(testBitOrImms(43, 0)); |
| RUN(testBitOrImms(10, 3)); |
| RUN(testBitOrImms(42, 0xffffffffffffffff)); |
| RUN(testBitOrArgImm(43, 43)); |
| RUN(testBitOrArgImm(43, 0)); |
| RUN(testBitOrArgImm(10, 3)); |
| RUN(testBitOrArgImm(42, 0xffffffffffffffff)); |
| RUN(testBitOrImmArg(43, 43)); |
| RUN(testBitOrImmArg(43, 0)); |
| RUN(testBitOrImmArg(10, 3)); |
| RUN(testBitOrImmArg(42, 0xffffffffffffffff)); |
| RUN(testBitOrBitOrArgImmImm(2, 7, 3)); |
| RUN(testBitOrBitOrArgImmImm(1, 6, 6)); |
| RUN(testBitOrBitOrArgImmImm(0xffff, 24, 7)); |
| RUN(testBitOrImmBitOrArgImm(7, 2, 3)); |
| RUN(testBitOrImmBitOrArgImm(6, 1, 6)); |
| RUN(testBitOrImmBitOrArgImm(24, 0xffff, 7)); |
| RUN(testBitOrArgs32(43, 43)); |
| RUN(testBitOrArgs32(43, 0)); |
| RUN(testBitOrArgs32(10, 3)); |
| RUN(testBitOrArgs32(42, 0xffffffff)); |
| RUN(testBitOrSameArg32(43)); |
| RUN(testBitOrSameArg32(0)); |
| RUN(testBitOrSameArg32(3)); |
| RUN(testBitOrSameArg32(0xffffffff)); |
| RUN(testBitOrImms32(43, 43)); |
| RUN(testBitOrImms32(43, 0)); |
| RUN(testBitOrImms32(10, 3)); |
| RUN(testBitOrImms32(42, 0xffffffff)); |
| RUN(testBitOrArgImm32(43, 43)); |
| RUN(testBitOrArgImm32(43, 0)); |
| RUN(testBitOrArgImm32(10, 3)); |
| RUN(testBitOrArgImm32(42, 0xffffffff)); |
| RUN(testBitOrImmArg32(43, 43)); |
| RUN(testBitOrImmArg32(43, 0)); |
| RUN(testBitOrImmArg32(10, 3)); |
| RUN(testBitOrImmArg32(42, 0xffffffff)); |
| RUN(testBitOrBitOrArgImmImm32(2, 7, 3)); |
| RUN(testBitOrBitOrArgImmImm32(1, 6, 6)); |
| RUN(testBitOrBitOrArgImmImm32(0xffff, 24, 7)); |
| RUN(testBitOrImmBitOrArgImm32(7, 2, 3)); |
| RUN(testBitOrImmBitOrArgImm32(6, 1, 6)); |
| RUN(testBitOrImmBitOrArgImm32(24, 0xffff, 7)); |
| |
| RUN(testBitXorArgs(43, 43)); |
| RUN(testBitXorArgs(43, 0)); |
| RUN(testBitXorArgs(10, 3)); |
| RUN(testBitXorArgs(42, 0xffffffffffffffff)); |
| RUN(testBitXorSameArg(43)); |
| RUN(testBitXorSameArg(0)); |
| RUN(testBitXorSameArg(3)); |
| RUN(testBitXorSameArg(0xffffffffffffffff)); |
| RUN(testBitXorImms(43, 43)); |
| RUN(testBitXorImms(43, 0)); |
| RUN(testBitXorImms(10, 3)); |
| RUN(testBitXorImms(42, 0xffffffffffffffff)); |
| RUN(testBitXorArgImm(43, 43)); |
| RUN(testBitXorArgImm(43, 0)); |
| RUN(testBitXorArgImm(10, 3)); |
| RUN(testBitXorArgImm(42, 0xffffffffffffffff)); |
| RUN(testBitXorImmArg(43, 43)); |
| RUN(testBitXorImmArg(43, 0)); |
| RUN(testBitXorImmArg(10, 3)); |
| RUN(testBitXorImmArg(42, 0xffffffffffffffff)); |
| RUN(testBitXorBitXorArgImmImm(2, 7, 3)); |
| RUN(testBitXorBitXorArgImmImm(1, 6, 6)); |
| RUN(testBitXorBitXorArgImmImm(0xffff, 24, 7)); |
| RUN(testBitXorImmBitXorArgImm(7, 2, 3)); |
| RUN(testBitXorImmBitXorArgImm(6, 1, 6)); |
| RUN(testBitXorImmBitXorArgImm(24, 0xffff, 7)); |
| RUN(testBitXorArgs32(43, 43)); |
| RUN(testBitXorArgs32(43, 0)); |
| RUN(testBitXorArgs32(10, 3)); |
| RUN(testBitXorArgs32(42, 0xffffffff)); |
| RUN(testBitXorSameArg32(43)); |
| RUN(testBitXorSameArg32(0)); |
| RUN(testBitXorSameArg32(3)); |
| RUN(testBitXorSameArg32(0xffffffff)); |
| RUN(testBitXorImms32(43, 43)); |
| RUN(testBitXorImms32(43, 0)); |
| RUN(testBitXorImms32(10, 3)); |
| RUN(testBitXorImms32(42, 0xffffffff)); |
| RUN(testBitXorArgImm32(43, 43)); |
| RUN(testBitXorArgImm32(43, 0)); |
| RUN(testBitXorArgImm32(10, 3)); |
| RUN(testBitXorArgImm32(42, 0xffffffff)); |
| RUN(testBitXorImmArg32(43, 43)); |
| RUN(testBitXorImmArg32(43, 0)); |
| RUN(testBitXorImmArg32(10, 3)); |
| RUN(testBitXorImmArg32(42, 0xffffffff)); |
| RUN(testBitXorBitXorArgImmImm32(2, 7, 3)); |
| RUN(testBitXorBitXorArgImmImm32(1, 6, 6)); |
| RUN(testBitXorBitXorArgImmImm32(0xffff, 24, 7)); |
| RUN(testBitXorImmBitXorArgImm32(7, 2, 3)); |
| RUN(testBitXorImmBitXorArgImm32(6, 1, 6)); |
| RUN(testBitXorImmBitXorArgImm32(24, 0xffff, 7)); |
| |
| RUN(testShlArgs(1, 0)); |
| RUN(testShlArgs(1, 1)); |
| RUN(testShlArgs(1, 62)); |
| RUN(testShlArgs(0xffffffffffffffff, 0)); |
| RUN(testShlArgs(0xffffffffffffffff, 1)); |
| RUN(testShlArgs(0xffffffffffffffff, 63)); |
| RUN(testShlImms(1, 0)); |
| RUN(testShlImms(1, 1)); |
| RUN(testShlImms(1, 62)); |
| RUN(testShlImms(1, 65)); |
| RUN(testShlImms(0xffffffffffffffff, 0)); |
| RUN(testShlImms(0xffffffffffffffff, 1)); |
| RUN(testShlImms(0xffffffffffffffff, 63)); |
| RUN(testShlArgImm(1, 0)); |
| RUN(testShlArgImm(1, 1)); |
| RUN(testShlArgImm(1, 62)); |
| RUN(testShlArgImm(1, 65)); |
| RUN(testShlArgImm(0xffffffffffffffff, 0)); |
| RUN(testShlArgImm(0xffffffffffffffff, 1)); |
| RUN(testShlArgImm(0xffffffffffffffff, 63)); |
| RUN(testShlArgs32(1, 0)); |
| RUN(testShlArgs32(1, 1)); |
| RUN(testShlArgs32(1, 62)); |
| RUN(testShlImms32(1, 33)); |
| RUN(testShlArgs32(0xffffffff, 0)); |
| RUN(testShlArgs32(0xffffffff, 1)); |
| RUN(testShlArgs32(0xffffffff, 63)); |
| RUN(testShlImms32(1, 0)); |
| RUN(testShlImms32(1, 1)); |
| RUN(testShlImms32(1, 62)); |
| RUN(testShlImms32(1, 33)); |
| RUN(testShlImms32(0xffffffff, 0)); |
| RUN(testShlImms32(0xffffffff, 1)); |
| RUN(testShlImms32(0xffffffff, 63)); |
| RUN(testShlArgImm32(1, 0)); |
| RUN(testShlArgImm32(1, 1)); |
| RUN(testShlArgImm32(1, 62)); |
| RUN(testShlArgImm32(0xffffffff, 0)); |
| RUN(testShlArgImm32(0xffffffff, 1)); |
| RUN(testShlArgImm32(0xffffffff, 63)); |
| |
| RUN(testSShrArgs(1, 0)); |
| RUN(testSShrArgs(1, 1)); |
| RUN(testSShrArgs(1, 62)); |
| RUN(testSShrArgs(0xffffffffffffffff, 0)); |
| RUN(testSShrArgs(0xffffffffffffffff, 1)); |
| RUN(testSShrArgs(0xffffffffffffffff, 63)); |
| RUN(testSShrImms(1, 0)); |
| RUN(testSShrImms(1, 1)); |
| RUN(testSShrImms(1, 62)); |
| RUN(testSShrImms(1, 65)); |
| RUN(testSShrImms(0xffffffffffffffff, 0)); |
| RUN(testSShrImms(0xffffffffffffffff, 1)); |
| RUN(testSShrImms(0xffffffffffffffff, 63)); |
| RUN(testSShrArgImm(1, 0)); |
| RUN(testSShrArgImm(1, 1)); |
| RUN(testSShrArgImm(1, 62)); |
| RUN(testSShrArgImm(1, 65)); |
| RUN(testSShrArgImm(0xffffffffffffffff, 0)); |
| RUN(testSShrArgImm(0xffffffffffffffff, 1)); |
| RUN(testSShrArgImm(0xffffffffffffffff, 63)); |
| RUN(testSShrArgs32(1, 0)); |
| RUN(testSShrArgs32(1, 1)); |
| RUN(testSShrArgs32(1, 62)); |
| RUN(testSShrArgs32(1, 33)); |
| RUN(testSShrArgs32(0xffffffff, 0)); |
| RUN(testSShrArgs32(0xffffffff, 1)); |
| RUN(testSShrArgs32(0xffffffff, 63)); |
| RUN(testSShrImms32(1, 0)); |
| RUN(testSShrImms32(1, 1)); |
| RUN(testSShrImms32(1, 62)); |
| RUN(testSShrImms32(1, 33)); |
| RUN(testSShrImms32(0xffffffff, 0)); |
| RUN(testSShrImms32(0xffffffff, 1)); |
| RUN(testSShrImms32(0xffffffff, 63)); |
| RUN(testSShrArgImm32(1, 0)); |
| RUN(testSShrArgImm32(1, 1)); |
| RUN(testSShrArgImm32(1, 62)); |
| RUN(testSShrArgImm32(0xffffffff, 0)); |
| RUN(testSShrArgImm32(0xffffffff, 1)); |
| RUN(testSShrArgImm32(0xffffffff, 63)); |
| |
| RUN(testZShrArgs(1, 0)); |
| RUN(testZShrArgs(1, 1)); |
| RUN(testZShrArgs(1, 62)); |
| RUN(testZShrArgs(0xffffffffffffffff, 0)); |
| RUN(testZShrArgs(0xffffffffffffffff, 1)); |
| RUN(testZShrArgs(0xffffffffffffffff, 63)); |
| RUN(testZShrImms(1, 0)); |
| RUN(testZShrImms(1, 1)); |
| RUN(testZShrImms(1, 62)); |
| RUN(testZShrImms(1, 65)); |
| RUN(testZShrImms(0xffffffffffffffff, 0)); |
| RUN(testZShrImms(0xffffffffffffffff, 1)); |
| RUN(testZShrImms(0xffffffffffffffff, 63)); |
| RUN(testZShrArgImm(1, 0)); |
| RUN(testZShrArgImm(1, 1)); |
| RUN(testZShrArgImm(1, 62)); |
| RUN(testZShrArgImm(1, 65)); |
| RUN(testZShrArgImm(0xffffffffffffffff, 0)); |
| RUN(testZShrArgImm(0xffffffffffffffff, 1)); |
| RUN(testZShrArgImm(0xffffffffffffffff, 63)); |
| RUN(testZShrArgs32(1, 0)); |
| RUN(testZShrArgs32(1, 1)); |
| RUN(testZShrArgs32(1, 62)); |
| RUN(testZShrArgs32(1, 33)); |
| RUN(testZShrArgs32(0xffffffff, 0)); |
| RUN(testZShrArgs32(0xffffffff, 1)); |
| RUN(testZShrArgs32(0xffffffff, 63)); |
| RUN(testZShrImms32(1, 0)); |
| RUN(testZShrImms32(1, 1)); |
| RUN(testZShrImms32(1, 62)); |
| RUN(testZShrImms32(1, 33)); |
| RUN(testZShrImms32(0xffffffff, 0)); |
| RUN(testZShrImms32(0xffffffff, 1)); |
| RUN(testZShrImms32(0xffffffff, 63)); |
| RUN(testZShrArgImm32(1, 0)); |
| RUN(testZShrArgImm32(1, 1)); |
| RUN(testZShrArgImm32(1, 62)); |
| RUN(testZShrArgImm32(0xffffffff, 0)); |
| RUN(testZShrArgImm32(0xffffffff, 1)); |
| RUN(testZShrArgImm32(0xffffffff, 63)); |
| |
| RUN(testStore(44)); |
| RUN(testStoreConstant(49)); |
| RUN(testStoreConstantPtr(49)); |
| RUN(testTrunc((static_cast<int64_t>(1) << 40) + 42)); |
| RUN(testAdd1(45)); |
| RUN(testAdd1Ptr(51)); |
| RUN(testAdd1Ptr(bitwise_cast<intptr_t>(vm))); |
| RUN(testNeg32(52)); |
| RUN(testNegPtr(53)); |
| RUN(testStoreAddLoad(46)); |
| RUN(testStoreSubLoad(46)); |
| RUN(testStoreAddLoadInterference(52)); |
| RUN(testStoreAddAndLoad(47, 0xffff)); |
| RUN(testStoreAddAndLoad(470000, 0xffff)); |
| RUN(testStoreNegLoad32(54)); |
| RUN(testStoreNegLoadPtr(55)); |
| RUN(testAdd1Uncommuted(48)); |
| RUN(testLoadOffset()); |
| RUN(testLoadOffsetNotConstant()); |
| RUN(testLoadOffsetUsingAdd()); |
| RUN(testLoadOffsetUsingAddInterference()); |
| RUN(testLoadOffsetUsingAddNotConstant()); |
| RUN(testFramePointer()); |
| RUN(testStackSlot()); |
| RUN(testLoadFromFramePointer()); |
| RUN(testStoreLoadStackSlot(50)); |
| |
| RUN(testBranch()); |
| RUN(testBranchPtr()); |
| RUN(testDiamond()); |
| RUN(testBranchNotEqual()); |
| RUN(testBranchNotEqualCommute()); |
| RUN(testBranchNotEqualNotEqual()); |
| RUN(testBranchEqual()); |
| RUN(testBranchEqualEqual()); |
| RUN(testBranchEqualCommute()); |
| RUN(testBranchEqualEqual1()); |
| RUN(testBranchFold(42)); |
| RUN(testBranchFold(0)); |
| RUN(testDiamondFold(42)); |
| RUN(testDiamondFold(0)); |
| RUN(testBranchNotEqualFoldPtr(42)); |
| RUN(testBranchNotEqualFoldPtr(0)); |
| RUN(testBranchEqualFoldPtr(42)); |
| RUN(testBranchEqualFoldPtr(0)); |
| |
| RUN(testComplex(64, 128)); |
| RUN(testComplex(64, 256)); |
| RUN(testComplex(64, 384)); |
| RUN(testComplex(4, 128)); |
| RUN(testComplex(4, 256)); |
| RUN(testComplex(4, 384)); |
| |
| RUN(testSimplePatchpoint()); |
| RUN(testSimpleCheck()); |
| RUN(testCheckLessThan()); |
| RUN(testCheckMegaCombo()); |
| |
| RUN(testCompare(Equal, 42, 42)); |
| RUN(testCompare(NotEqual, 42, 42)); |
| RUN(testCompare(LessThan, 42, 42)); |
| RUN(testCompare(GreaterThan, 42, 42)); |
| RUN(testCompare(LessEqual, 42, 42)); |
| RUN(testCompare(GreaterEqual, 42, 42)); |
| RUN(testCompare(Below, 42, 42)); |
| RUN(testCompare(Above, 42, 42)); |
| RUN(testCompare(BelowEqual, 42, 42)); |
| RUN(testCompare(AboveEqual, 42, 42)); |
| |
| RUN(testCompare(BitAnd, 42, 42)); |
| RUN(testCompare(BitAnd, 42, 0)); |
| |
| RUN(testLoad<int32_t>(Load, 60)); |
| RUN(testLoad<int32_t>(Load, -60)); |
| RUN(testLoad<int32_t>(Load, 1000)); |
| RUN(testLoad<int32_t>(Load, -1000)); |
| RUN(testLoad<int32_t>(Load, 1000000)); |
| RUN(testLoad<int32_t>(Load, -1000000)); |
| RUN(testLoad<int32_t>(Load, 1000000000)); |
| RUN(testLoad<int32_t>(Load, -1000000000)); |
| |
| RUN(testLoad<int8_t>(Load8S, 60)); |
| RUN(testLoad<int8_t>(Load8S, -60)); |
| RUN(testLoad<int8_t>(Load8S, 1000)); |
| RUN(testLoad<int8_t>(Load8S, -1000)); |
| RUN(testLoad<int8_t>(Load8S, 1000000)); |
| RUN(testLoad<int8_t>(Load8S, -1000000)); |
| RUN(testLoad<int8_t>(Load8S, 1000000000)); |
| RUN(testLoad<int8_t>(Load8S, -1000000000)); |
| |
| RUN(testLoad<uint8_t>(Load8Z, 60)); |
| RUN(testLoad<uint8_t>(Load8Z, -60)); |
| RUN(testLoad<uint8_t>(Load8Z, 1000)); |
| RUN(testLoad<uint8_t>(Load8Z, -1000)); |
| RUN(testLoad<uint8_t>(Load8Z, 1000000)); |
| RUN(testLoad<uint8_t>(Load8Z, -1000000)); |
| RUN(testLoad<uint8_t>(Load8Z, 1000000000)); |
| RUN(testLoad<uint8_t>(Load8Z, -1000000000)); |
| |
| RUN(testLoad<int16_t>(Load16S, 60)); |
| RUN(testLoad<int16_t>(Load16S, -60)); |
| RUN(testLoad<int16_t>(Load16S, 1000)); |
| RUN(testLoad<int16_t>(Load16S, -1000)); |
| RUN(testLoad<int16_t>(Load16S, 1000000)); |
| RUN(testLoad<int16_t>(Load16S, -1000000)); |
| RUN(testLoad<int16_t>(Load16S, 1000000000)); |
| RUN(testLoad<int16_t>(Load16S, -1000000000)); |
| |
| RUN(testLoad<uint16_t>(Load16Z, 60)); |
| RUN(testLoad<uint16_t>(Load16Z, -60)); |
| RUN(testLoad<uint16_t>(Load16Z, 1000)); |
| RUN(testLoad<uint16_t>(Load16Z, -1000)); |
| RUN(testLoad<uint16_t>(Load16Z, 1000000)); |
| RUN(testLoad<uint16_t>(Load16Z, -1000000)); |
| RUN(testLoad<uint16_t>(Load16Z, 1000000000)); |
| RUN(testLoad<uint16_t>(Load16Z, -1000000000)); |
| |
| RUN(testSpillGP()); |
| |
| RUN(testCallSimple(1, 2)); |
| RUN(testCallFunctionWithHellaArguments()); |
| |
| RUN(testReturnDouble(0.0)); |
| RUN(testReturnDouble(-0.0)); |
| RUN(testReturnDouble(42.5)); |
| |
| RUN(testCallSimpleDouble(1, 2)); |
| RUN(testCallFunctionWithHellaDoubleArguments()); |
| |
| RUN(testChillDiv(4, 2, 2)); |
| RUN(testChillDiv(1, 0, 0)); |
| RUN(testChillDiv(0, 0, 0)); |
| RUN(testChillDiv(1, -1, -1)); |
| RUN(testChillDiv(-2147483647 - 1, 0, 0)); |
| RUN(testChillDiv(-2147483647 - 1, 1, -2147483647 - 1)); |
| RUN(testChillDiv(-2147483647 - 1, -1, -2147483647 - 1)); |
| RUN(testChillDiv(-2147483647 - 1, 2, -1073741824)); |
| RUN(testChillDiv64(4, 2, 2)); |
| RUN(testChillDiv64(1, 0, 0)); |
| RUN(testChillDiv64(0, 0, 0)); |
| RUN(testChillDiv64(1, -1, -1)); |
| RUN(testChillDiv64(-9223372036854775807ll - 1, 0, 0)); |
| RUN(testChillDiv64(-9223372036854775807ll - 1, 1, -9223372036854775807ll - 1)); |
| RUN(testChillDiv64(-9223372036854775807ll - 1, -1, -9223372036854775807ll - 1)); |
| RUN(testChillDiv64(-9223372036854775807ll - 1, 2, -4611686018427387904)); |
| RUN(testChillDivTwice(4, 2, 6, 2, 5)); |
| RUN(testChillDivTwice(4, 0, 6, 2, 3)); |
| RUN(testChillDivTwice(4, 2, 6, 0, 2)); |
| |
| if (tasks.isEmpty()) |
| usage(); |
| |
| Lock lock; |
| |
| Vector<ThreadIdentifier> threads; |
| for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) { |
| threads.append( |
| createThread( |
| "testb3 thread", |
| [&] () { |
| for (;;) { |
| RefPtr<SharedTask<void()>> task; |
| { |
| LockHolder locker(lock); |
| if (tasks.isEmpty()) |
| return; |
| task = tasks.takeFirst(); |
| } |
| |
| task->run(); |
| } |
| })); |
| } |
| |
| for (ThreadIdentifier thread : threads) |
| waitForThreadCompletion(thread); |
| } |
| |
| } // anonymous namespace |
| |
| #else // ENABLE(B3_JIT) |
| |
| static void run(const char*) |
| { |
| dataLog("B3 JIT is not enabled.\n"); |
| } |
| |
| #endif // ENABLE(B3_JIT) |
| |
| int main(int argc, char** argv) |
| { |
| const char* filter = nullptr; |
| switch (argc) { |
| case 1: |
| break; |
| case 2: |
| filter = argv[1]; |
| break; |
| default: |
| usage(); |
| break; |
| } |
| |
| run(filter); |
| return 0; |
| } |
| |