haikuwebkit/Source/JavaScriptCore/b3/B3ValueKeyInlines.h

76 lines
2.3 KiB
C
Raw Permalink Normal View History

B3 should be able to compile a program with a double constant https://bugs.webkit.org/show_bug.cgi?id=151002 Reviewed by Benjamin Poulain. This implements a bunch of annoying stuff that is necessary to support constants that need a data section, such as double constants on X86_64: - B3::Procedure can now tell you what to keep alive in addition to the MacroAssemblerCodeRef. We call this the B3::OpaqueByproducts. It's the client's responsibility to keep this alive after calling B3::generate(). - Added a new helper for compiling B3 code, called B3::Compilation. Constructing a Compilation runs the compiler. Then you can pass around a Compilation the way you would have passed around a MacroAssemblerCodeRef. - Added a constant motion phase, called moveConstants(). This does very simple constant hoisting/sinking: it makes sure that each constant is only materialized in one place in each basic block. It uses a DataSection, which is a kind of OpaqueByproduct, to store double constants. - The way I wanted to do constant motion is to basically track what constants are of interest and then recreate them as needed, so the original Values become irrelevant in the process. To do that, I needed an abstraction that is almost identical to the DFG PureValue abstraction that we use for CSE. So, I created such a thing, and called it ValueKey. It can be used to compare and hash pure Values, and to recreate them as needed. - Fixed the lowering's handling of constants so that we don't perturb the placement of the constant materializations. * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): (JSC::MacroAssemblerX86Common::moveZeroToDouble): (JSC::MacroAssemblerX86Common::branchDoubleNonZero): * b3/B3Common.h: (JSC::B3::isIdentical): (JSC::B3::isRepresentableAsImpl): * b3/B3Compilation.cpp: Added. (JSC::B3::Compilation::Compilation): (JSC::B3::Compilation::~Compilation): * b3/B3Compilation.h: Added. (JSC::B3::Compilation::code): * b3/B3ConstDoubleValue.h: (JSC::B3::ConstDoubleValue::accepts): Deleted. * b3/B3DataSection.cpp: Added. (JSC::B3::DataSection::DataSection): (JSC::B3::DataSection::~DataSection): (JSC::B3::DataSection::dump): * b3/B3DataSection.h: Added. (JSC::B3::DataSection::data): (JSC::B3::DataSection::size): * b3/B3Generate.cpp: (JSC::B3::generate): (JSC::B3::generateToAir): * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::imm): (JSC::B3::Air::LowerToAir::immOrTmp): (JSC::B3::Air::LowerToAir::fillStackmap): (JSC::B3::Air::LowerToAir::lower): (JSC::B3::Air::LowerToAir::immForMove): Deleted. (JSC::B3::Air::LowerToAir::immOrTmpForMove): Deleted. * b3/B3MoveConstants.cpp: Added. (JSC::B3::moveConstants): * b3/B3MoveConstants.h: Added. * b3/B3OpaqueByproduct.h: Added. (JSC::B3::OpaqueByproduct::OpaqueByproduct): (JSC::B3::OpaqueByproduct::~OpaqueByproduct): * b3/B3OpaqueByproducts.cpp: Added. (JSC::B3::OpaqueByproducts::OpaqueByproducts): (JSC::B3::OpaqueByproducts::~OpaqueByproducts): (JSC::B3::OpaqueByproducts::add): (JSC::B3::OpaqueByproducts::dump): * b3/B3OpaqueByproducts.h: Added. (JSC::B3::OpaqueByproducts::count): * b3/B3Opcode.h: (JSC::B3::constPtrOpcode): * b3/B3Procedure.cpp: (JSC::B3::Procedure::Procedure): (JSC::B3::Procedure::dump): (JSC::B3::Procedure::blocksInPreOrder): (JSC::B3::Procedure::deleteValue): (JSC::B3::Procedure::addDataSection): (JSC::B3::Procedure::addValueIndex): * b3/B3Procedure.h: (JSC::B3::Procedure::lastPhaseName): (JSC::B3::Procedure::byproducts): (JSC::B3::Procedure::takeByproducts): * b3/B3Type.h: * b3/B3Value.cpp: (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::performSubstitution): * b3/B3Value.h: * b3/B3ValueKey.cpp: Added. (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::type): (JSC::B3::ValueKey::childIndex): (JSC::B3::ValueKey::value): (JSC::B3::ValueKey::doubleValue): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::operator!=): (JSC::B3::ValueKey::hash): (JSC::B3::ValueKey::operator bool): (JSC::B3::ValueKey::canMaterialize): (JSC::B3::ValueKey::isHashTableDeletedValue): (JSC::B3::ValueKeyHash::hash): (JSC::B3::ValueKeyHash::equal): * b3/B3ValueKeyInlines.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::child): * b3/air/AirCode.cpp: (JSC::B3::Air::Code::Code): * b3/air/AirCode.h: (JSC::B3::Air::Code::proc): (JSC::B3::Air::Code::lastPhaseName): * b3/air/AirOpcode.opcodes: * b3/testb3.cpp: (JSC::B3::compile): (JSC::B3::invoke): (JSC::B3::compileAndRun): (JSC::B3::test42): (JSC::B3::testBranch): (JSC::B3::testBranchPtr): (JSC::B3::testDiamond): (JSC::B3::testBranchNotEqual): (JSC::B3::testBranchNotEqualCommute): (JSC::B3::testBranchNotEqualNotEqual): (JSC::B3::testBranchEqual): (JSC::B3::testBranchEqualEqual): (JSC::B3::testBranchEqualCommute): (JSC::B3::testBranchEqualEqual1): (JSC::B3::testBranchFold): (JSC::B3::testSimpleCheck): (JSC::B3::testCompare): (JSC::B3::testReturnDouble): (JSC::B3::run): Canonical link: https://commits.webkit.org/169260@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192183 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-11-10 00:01:24 +00:00
/*
* 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.
*/
#pragma once
B3 should be able to compile a program with a double constant https://bugs.webkit.org/show_bug.cgi?id=151002 Reviewed by Benjamin Poulain. This implements a bunch of annoying stuff that is necessary to support constants that need a data section, such as double constants on X86_64: - B3::Procedure can now tell you what to keep alive in addition to the MacroAssemblerCodeRef. We call this the B3::OpaqueByproducts. It's the client's responsibility to keep this alive after calling B3::generate(). - Added a new helper for compiling B3 code, called B3::Compilation. Constructing a Compilation runs the compiler. Then you can pass around a Compilation the way you would have passed around a MacroAssemblerCodeRef. - Added a constant motion phase, called moveConstants(). This does very simple constant hoisting/sinking: it makes sure that each constant is only materialized in one place in each basic block. It uses a DataSection, which is a kind of OpaqueByproduct, to store double constants. - The way I wanted to do constant motion is to basically track what constants are of interest and then recreate them as needed, so the original Values become irrelevant in the process. To do that, I needed an abstraction that is almost identical to the DFG PureValue abstraction that we use for CSE. So, I created such a thing, and called it ValueKey. It can be used to compare and hash pure Values, and to recreate them as needed. - Fixed the lowering's handling of constants so that we don't perturb the placement of the constant materializations. * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): (JSC::MacroAssemblerX86Common::moveZeroToDouble): (JSC::MacroAssemblerX86Common::branchDoubleNonZero): * b3/B3Common.h: (JSC::B3::isIdentical): (JSC::B3::isRepresentableAsImpl): * b3/B3Compilation.cpp: Added. (JSC::B3::Compilation::Compilation): (JSC::B3::Compilation::~Compilation): * b3/B3Compilation.h: Added. (JSC::B3::Compilation::code): * b3/B3ConstDoubleValue.h: (JSC::B3::ConstDoubleValue::accepts): Deleted. * b3/B3DataSection.cpp: Added. (JSC::B3::DataSection::DataSection): (JSC::B3::DataSection::~DataSection): (JSC::B3::DataSection::dump): * b3/B3DataSection.h: Added. (JSC::B3::DataSection::data): (JSC::B3::DataSection::size): * b3/B3Generate.cpp: (JSC::B3::generate): (JSC::B3::generateToAir): * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::imm): (JSC::B3::Air::LowerToAir::immOrTmp): (JSC::B3::Air::LowerToAir::fillStackmap): (JSC::B3::Air::LowerToAir::lower): (JSC::B3::Air::LowerToAir::immForMove): Deleted. (JSC::B3::Air::LowerToAir::immOrTmpForMove): Deleted. * b3/B3MoveConstants.cpp: Added. (JSC::B3::moveConstants): * b3/B3MoveConstants.h: Added. * b3/B3OpaqueByproduct.h: Added. (JSC::B3::OpaqueByproduct::OpaqueByproduct): (JSC::B3::OpaqueByproduct::~OpaqueByproduct): * b3/B3OpaqueByproducts.cpp: Added. (JSC::B3::OpaqueByproducts::OpaqueByproducts): (JSC::B3::OpaqueByproducts::~OpaqueByproducts): (JSC::B3::OpaqueByproducts::add): (JSC::B3::OpaqueByproducts::dump): * b3/B3OpaqueByproducts.h: Added. (JSC::B3::OpaqueByproducts::count): * b3/B3Opcode.h: (JSC::B3::constPtrOpcode): * b3/B3Procedure.cpp: (JSC::B3::Procedure::Procedure): (JSC::B3::Procedure::dump): (JSC::B3::Procedure::blocksInPreOrder): (JSC::B3::Procedure::deleteValue): (JSC::B3::Procedure::addDataSection): (JSC::B3::Procedure::addValueIndex): * b3/B3Procedure.h: (JSC::B3::Procedure::lastPhaseName): (JSC::B3::Procedure::byproducts): (JSC::B3::Procedure::takeByproducts): * b3/B3Type.h: * b3/B3Value.cpp: (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::performSubstitution): * b3/B3Value.h: * b3/B3ValueKey.cpp: Added. (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::type): (JSC::B3::ValueKey::childIndex): (JSC::B3::ValueKey::value): (JSC::B3::ValueKey::doubleValue): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::operator!=): (JSC::B3::ValueKey::hash): (JSC::B3::ValueKey::operator bool): (JSC::B3::ValueKey::canMaterialize): (JSC::B3::ValueKey::isHashTableDeletedValue): (JSC::B3::ValueKeyHash::hash): (JSC::B3::ValueKeyHash::equal): * b3/B3ValueKeyInlines.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::child): * b3/air/AirCode.cpp: (JSC::B3::Air::Code::Code): * b3/air/AirCode.h: (JSC::B3::Air::Code::proc): (JSC::B3::Air::Code::lastPhaseName): * b3/air/AirOpcode.opcodes: * b3/testb3.cpp: (JSC::B3::compile): (JSC::B3::invoke): (JSC::B3::compileAndRun): (JSC::B3::test42): (JSC::B3::testBranch): (JSC::B3::testBranchPtr): (JSC::B3::testDiamond): (JSC::B3::testBranchNotEqual): (JSC::B3::testBranchNotEqualCommute): (JSC::B3::testBranchNotEqualNotEqual): (JSC::B3::testBranchEqual): (JSC::B3::testBranchEqualEqual): (JSC::B3::testBranchEqualCommute): (JSC::B3::testBranchEqualEqual1): (JSC::B3::testBranchFold): (JSC::B3::testSimpleCheck): (JSC::B3::testCompare): (JSC::B3::testReturnDouble): (JSC::B3::run): Canonical link: https://commits.webkit.org/169260@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192183 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-11-10 00:01:24 +00:00
#if ENABLE(B3_JIT)
#include "B3Procedure.h"
#include "B3Value.h"
#include "B3ValueKey.h"
namespace JSC { namespace B3 {
Add Pre/Post-Indexed Address Mode to Air for ARM64 https://bugs.webkit.org/show_bug.cgi?id=228047 Reviewed by Phil Pizlo. Pre-indexed addressing means that the address is the sum of the value in the 64-bit base register and an offset, and the address is then written back to the base register. And post-indexed addressing means that the address is the value in the 64-bit base register, and the sum of the address and the offset is then written back to the base register. They are relatively common for loops to iterate over an array by increasing/decreasing a pointer into the array at each iteration. With such an addressing mode, the instruction selector can merge the increment and access the array. ##################################### ## Pre-Index Address Mode For Load ## ##################################### LDR Wt, [Xn, #imm]! In B3 Reduction Strength, since we have this reduction rule: Turn this: Load(Add(address, offset1), offset = offset2) Into this: Load(address, offset = offset1 + offset2) Then, the equivalent pattern is: address = Add(base, offset) ... memory = Load(base, offset) First, we convert it to the canonical form: address = Add(base, offset) newMemory = Load(base, offset) // move the memory to just after the address ... memory = Identity(newMemory) Next, lower to Air: Move %base, %address Move (%address, prefix(offset)), %newMemory ###################################### ## Post-Index Address Mode For Load ## ###################################### LDR Wt, [Xn], #imm Then, the equivalent pattern is: memory = Load(base, 0) ... address = Add(base, offset) First, we convert it to the canonical form: newOffset = Constant newAddress = Add(base, offset) memory = Load(base, 0) // move the offset and address to just before the memory ... offset = Identity(newOffset) address = Identity(newAddress) Next, lower to Air: Move %base, %newAddress Move (%newAddress, postfix(offset)), %memory ############################# ## Pattern Match Algorithm ## ############################# To detect the pattern for prefix/postfix increment address is tricky due to the structure in B3 IR. The algorithm used in this patch is to collect the first valid values (add/load), then search for any paired value (load/add) to match all of them. In worst case, the runtime complexity is O(n^2) when n is the number of all values. After collecting two sets of candidates, we match the prefix incremental address first since it seems more beneficial to the compiler (shown in the next section). And then, go for the postfix one. ############################################## ## Test for Pre/Post-Increment Address Mode ## ############################################## Given Loop with Pre-Increment: int64_t ldr_pre(int64_t *p) { int64_t res = 0; while (res < 10) res += *++p; return res; } B3 IR: ------------------------------------------------------ BB#0: ; frequency = 1.000000 Int64 b@0 = Const64(0) Int64 b@2 = ArgumentReg(%x0) Void b@20 = Upsilon($0(b@0), ^18, WritesLocalState) Void b@21 = Upsilon(b@2, ^19, WritesLocalState) Void b@4 = Jump(Terminal) Successors: #1 BB#1: ; frequency = 1.000000 Predecessors: #0, #2 Int64 b@18 = Phi(ReadsLocalState) Int64 b@19 = Phi(ReadsLocalState) Int64 b@7 = Const64(10) Int32 b@8 = AboveEqual(b@18, $10(b@7)) Void b@9 = Branch(b@8, Terminal) Successors: Then:#3, Else:#2 BB#2: ; frequency = 1.000000 Predecessors: #1 Int64 b@10 = Const64(8) Int64 b@11 = Add(b@19, $8(b@10)) Int64 b@13 = Load(b@11, ControlDependent|Reads:Top) Int64 b@14 = Add(b@18, b@13) Void b@22 = Upsilon(b@14, ^18, WritesLocalState) Void b@23 = Upsilon(b@11, ^19, WritesLocalState) Void b@16 = Jump(Terminal) Successors: #1 BB#3: ; frequency = 1.000000 Predecessors: #1 Void b@17 = Return(b@18, Terminal) Variables: Int64 var0 Int64 var1 ------------------------------------------------------ W/O Pre-Increment Address Mode: ------------------------------------------------------ ... BB#2: ; frequency = 1.000000 Predecessors: #1 Move $8, %x3, $8(b@12) Add64 $8, %x0, %x1, b@11 Move (%x0,%x3), %x0, b@13 Add64 %x0, %x2, %x2, b@14 Move %x1, %x0, b@23 Jump b@16 Successors: #1 ... ------------------------------------------------------ W/ Pre-Increment Address Mode: ------------------------------------------------------ ... BB#2: ; frequency = 1.000000 Predecessors: #1 MoveWithIncrement64 (%x0,Pre($8)), %x2, b@13 Add64 %x2, %x1, %x1, b@14 Jump b@16 Successors: #1 ... ------------------------------------------------------ Given Loop with Post-Increment: int64_t ldr_pre(int64_t *p) { int64_t res = 0; while (res < 10) res += *p++; return res; } B3 IR: ------------------------------------------------------ BB#0: ; frequency = 1.000000 Int64 b@0 = Const64(0) Int64 b@2 = ArgumentReg(%x0) Void b@20 = Upsilon($0(b@0), ^18, WritesLocalState) Void b@21 = Upsilon(b@2, ^19, WritesLocalState) Void b@4 = Jump(Terminal) Successors: #1 BB#1: ; frequency = 1.000000 Predecessors: #0, #2 Int64 b@18 = Phi(ReadsLocalState) Int64 b@19 = Phi(ReadsLocalState) Int64 b@7 = Const64(10) Int32 b@8 = AboveEqual(b@18, $10(b@7)) Void b@9 = Branch(b@8, Terminal) Successors: Then:#3, Else:#2 BB#2: ; frequency = 1.000000 Predecessors: #1 Int64 b@10 = Load(b@19, ControlDependent|Reads:Top) Int64 b@11 = Add(b@18, b@10) Int64 b@12 = Const64(8) Int64 b@13 = Add(b@19, $8(b@12)) Void b@22 = Upsilon(b@11, ^18, WritesLocalState) Void b@23 = Upsilon(b@13, ^19, WritesLocalState) Void b@16 = Jump(Terminal) Successors: #1 BB#3: ; frequency = 1.000000 Predecessors: #1 Void b@17 = Return(b@18, Terminal) Variables: Int64 var0 Int64 var1 ------------------------------------------------------ W/O Post-Increment Address Mode: ------------------------------------------------------ ... BB#2: ; frequency = 1.000000 Predecessors: #1 Move (%x0), %x2, b@10 Add64 %x2, %x1, %x1, b@11 Add64 $8, %x0, %x0, b@13 Jump b@16 Successors: #1 ... ------------------------------------------------------ W/ Post-Increment Address Mode: ------------------------------------------------------ ... BB#2: ; frequency = 1.000000 Predecessors: #1 MoveWithIncrement64 (%x0,Post($8)), %x2, b@10 Add64 %x2, %x1, %x1, b@11 Jump b@16 Successors: #1 ... ------------------------------------------------------ * Sources.txt: * assembler/AbstractMacroAssembler.h: (JSC::AbstractMacroAssembler::PreIndexAddress::PreIndexAddress): (JSC::AbstractMacroAssembler::PostIndexAddress::PostIndexAddress): * assembler/MacroAssemblerARM64.h: (JSC::MacroAssemblerARM64::load64): (JSC::MacroAssemblerARM64::load32): (JSC::MacroAssemblerARM64::store64): (JSC::MacroAssemblerARM64::store32): * assembler/testmasm.cpp: (JSC::testStorePrePostIndex32): (JSC::testStorePrePostIndex64): (JSC::testLoadPrePostIndex32): (JSC::testLoadPrePostIndex64): * b3/B3CanonicalizePrePostIncrements.cpp: Added. (JSC::B3::canonicalizePrePostIncrements): * b3/B3CanonicalizePrePostIncrements.h: Copied from Source/JavaScriptCore/b3/B3ValueKeyInlines.h. * b3/B3Generate.cpp: (JSC::B3::generateToAir): * b3/B3LowerToAir.cpp: * b3/B3ValueKey.h: * b3/B3ValueKeyInlines.h: (JSC::B3::ValueKey::ValueKey): * b3/air/AirArg.cpp: (JSC::B3::Air::Arg::jsHash const): (JSC::B3::Air::Arg::dump const): (WTF::printInternal): * b3/air/AirArg.h: (JSC::B3::Air::Arg::preIndex): (JSC::B3::Air::Arg::postIndex): (JSC::B3::Air::Arg::isPreIndex const): (JSC::B3::Air::Arg::isPostIndex const): (JSC::B3::Air::Arg::isMemory const): (JSC::B3::Air::Arg::base const): (JSC::B3::Air::Arg::offset const): (JSC::B3::Air::Arg::isGP const): (JSC::B3::Air::Arg::isFP const): (JSC::B3::Air::Arg::isValidPreIndexForm): (JSC::B3::Air::Arg::isValidPostIndexForm): (JSC::B3::Air::Arg::isValidForm const): (JSC::B3::Air::Arg::forEachTmpFast): (JSC::B3::Air::Arg::forEachTmp): (JSC::B3::Air::Arg::asPreIndexAddress const): (JSC::B3::Air::Arg::asPostIndexAddress const): * b3/air/AirOpcode.opcodes: * b3/air/opcode_generator.rb: * b3/testb3.h: * b3/testb3_3.cpp: (testLoadPreIndex32): (testLoadPreIndex64): (testLoadPostIndex32): (testLoadPostIndex64): (addShrTests): * jit/ExecutableAllocator.cpp: (JSC::jitWriteThunkGenerator): Canonical link: https://commits.webkit.org/240125@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@280493 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-07-30 20:44:47 +00:00
inline ValueKey::ValueKey(Value* child, int64_t value)
{
m_kind = Oops;
m_type = Void;
u.indices[0] = child->index();
u.value = value;
}
B3 opcodes should leave room for flags https://bugs.webkit.org/show_bug.cgi?id=162692 Reviewed by Keith Miller. Source/JavaScriptCore: It used to be that the main thing that determined what a Value did was the opcode. The Opcode was how you knew what subclass of Value you had. The opcode told you what the Value actually did. This change replaces Opcode with Kind, which is a tuple of opcode and other stuff. Opcodes are great, and that's how most compilers work. But opcodes are one-dimensional. Here is how this manifests. Say you have an opcode, like Load. You will be happy if your IR has one Load opcode. But then, you might add Load8S/Load8Z/Load16S/Load16Z opcodes, as we have done in B3. B3 has one dimension of Load opcodes, which determines something like the C type of the load. But in the very near future, we will want to add two more dimensions to Loads: - A flag to say if the load traps. - A flag to say if the load has acquire semantics. Mapping these three dimensions (type, trap, acquire) onto the one-dimensional Opcode space would create mayham: Load8S, Load8STrap, Load8SAcquire, Load8STrapAcquire, Load8Z, Load8ZTrap, etc. This happens in other parts of the IR. For example, we have a dimension of arithmetic operations: add, sub, mul, div, mod, etc. Then we have the chill flag. But since opcodes are one-dimensional, that means having ChillDiv and ChillMod, and tons of places in the compiler that case on both Div and ChillDiv, or case on both Mod and ChillMod, since they are only interested in the kind of arithmetic being done and not the chillness. Though the examples all involve bits (chill or not, trapping or not, etc), I can imagine other properties that behave more like small enums, like if we fill out more memory ordering modes other than just "acquire? yes/no". There will eventually have to be something like a std::memory_order associated with memory accesses. One approach to this problem is to have a Value subclass that contains fields with the meta data. I don't like this for two reasons: - In bug 162688, I want to make trapping memory accesses have stackmaps. This means that a trapping memory access would have a different Value subclass than a non-trapping memory access. So, this meta-data needs to channel into ValueType::accepts(). Currently that takes Opcode and nothing else. - Compiler IRs are all about making common tasks easy. If it becomes commonplace for opcodes to require a custom Value subclass just for a bit then that's not very easy. This change addresses this problem by making the compiler pass around Kinds rather than Opcodes. A Kind contains an Opcode as well as any number of opcode-specific bits. This change demonstrates how Kind should be used by converting chillness to it. Kind has hasIsChill(), isChill(), and setIsChill() methods. hasIsChill() is true only for Div and Mod. setIsChill() asserts if !hasIsChill(). If you want to create a Chill Div, you say chill(Div). IR dumps will print it like this: Int32 @38 = Div<Chill>(@36, @37, DFG:@24, ControlDependent) Where "Div<Chill>" is how a Kind that hasExtraBits() dumps itself. If a Kind does not hasExtraBits() (the normal case) then it dumps like a normal Opcode (without the "<>"). I replaced many uses of Opcode with Kind. New code has to be mindful that Opcode may not be the right way to summarize what a value does, and so in many cases it's better to carry around a Kind instead - especially if you will use it to stamp out new Values. Opcode is no longer sufficient to perform a dynamic Value cast, since that code now uses Kind. ValueKey now wants a Kind instead of an Opcode. All Value constructors now take Kind instead of Opcode. But most opcodes don't get any extra Kind bits, and so the code that operates on those opcodes is largely unchanged. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * b3/B3ArgumentRegValue.h: * b3/B3CCallValue.h: * b3/B3CheckValue.cpp: (JSC::B3::CheckValue::convertToAdd): (JSC::B3::CheckValue::CheckValue): * b3/B3CheckValue.h: (JSC::B3::CheckValue::accepts): * b3/B3Const32Value.h: * b3/B3Const64Value.h: * b3/B3ConstDoubleValue.h: * b3/B3ConstFloatValue.h: * b3/B3FenceValue.h: * b3/B3Kind.cpp: Added. (JSC::B3::Kind::dump): * b3/B3Kind.h: Added. (JSC::B3::Kind::Kind): (JSC::B3::Kind::opcode): (JSC::B3::Kind::setOpcode): (JSC::B3::Kind::hasExtraBits): (JSC::B3::Kind::hasIsChill): (JSC::B3::Kind::isChill): (JSC::B3::Kind::setIsChill): (JSC::B3::Kind::operator==): (JSC::B3::Kind::operator!=): (JSC::B3::Kind::hash): (JSC::B3::Kind::isHashTableDeletedValue): (JSC::B3::chill): (JSC::B3::KindHash::hash): (JSC::B3::KindHash::equal): * b3/B3LowerMacros.cpp: * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::lower): * b3/B3MemoryValue.h: * b3/B3Opcode.cpp: (WTF::printInternal): * b3/B3Opcode.h: * b3/B3PatchpointValue.h: (JSC::B3::PatchpointValue::accepts): * b3/B3ReduceStrength.cpp: * b3/B3SlotBaseValue.h: * b3/B3StackmapValue.cpp: (JSC::B3::StackmapValue::StackmapValue): * b3/B3StackmapValue.h: * b3/B3SwitchValue.h: (JSC::B3::SwitchValue::accepts): * b3/B3UpsilonValue.h: * b3/B3Validate.cpp: * b3/B3Value.cpp: (JSC::B3::Value::dump): (JSC::B3::Value::deepDump): (JSC::B3::Value::invertedCompare): (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::typeFor): (JSC::B3::Value::badKind): (JSC::B3::Value::badOpcode): Deleted. * b3/B3Value.h: * b3/B3ValueInlines.h: (JSC::B3::Value::as): * b3/B3ValueKey.cpp: (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::kind): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::hash): * b3/B3ValueKeyInlines.h: (JSC::B3::ValueKey::ValueKey): * b3/B3VariableValue.cpp: (JSC::B3::VariableValue::VariableValue): * b3/B3VariableValue.h: * b3/testb3.cpp: (JSC::B3::testChillDiv): (JSC::B3::testChillDivTwice): (JSC::B3::testChillDiv64): (JSC::B3::testChillModArg): (JSC::B3::testChillModArgs): (JSC::B3::testChillModImms): (JSC::B3::testChillModArg32): (JSC::B3::testChillModArgs32): (JSC::B3::testChillModImms32): (JSC::B3::testSwitchChillDiv): (JSC::B3::testEntrySwitchWithCommonPaths): (JSC::B3::testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint): * ftl/FTLOutput.cpp: (JSC::FTL::Output::chillDiv): (JSC::FTL::Output::chillMod): Websites/webkit.org: Updated the documentation to talk about Kind and the isChill bit, and to remove ChillDiv/ChillMod. * docs/b3/intermediate-representation.html: Canonical link: https://commits.webkit.org/180677@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206595 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-09-29 18:44:53 +00:00
inline ValueKey::ValueKey(Kind kind, Type type, Value* child)
: m_kind(kind)
B3 should be able to compile a program with a double constant https://bugs.webkit.org/show_bug.cgi?id=151002 Reviewed by Benjamin Poulain. This implements a bunch of annoying stuff that is necessary to support constants that need a data section, such as double constants on X86_64: - B3::Procedure can now tell you what to keep alive in addition to the MacroAssemblerCodeRef. We call this the B3::OpaqueByproducts. It's the client's responsibility to keep this alive after calling B3::generate(). - Added a new helper for compiling B3 code, called B3::Compilation. Constructing a Compilation runs the compiler. Then you can pass around a Compilation the way you would have passed around a MacroAssemblerCodeRef. - Added a constant motion phase, called moveConstants(). This does very simple constant hoisting/sinking: it makes sure that each constant is only materialized in one place in each basic block. It uses a DataSection, which is a kind of OpaqueByproduct, to store double constants. - The way I wanted to do constant motion is to basically track what constants are of interest and then recreate them as needed, so the original Values become irrelevant in the process. To do that, I needed an abstraction that is almost identical to the DFG PureValue abstraction that we use for CSE. So, I created such a thing, and called it ValueKey. It can be used to compare and hash pure Values, and to recreate them as needed. - Fixed the lowering's handling of constants so that we don't perturb the placement of the constant materializations. * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): (JSC::MacroAssemblerX86Common::moveZeroToDouble): (JSC::MacroAssemblerX86Common::branchDoubleNonZero): * b3/B3Common.h: (JSC::B3::isIdentical): (JSC::B3::isRepresentableAsImpl): * b3/B3Compilation.cpp: Added. (JSC::B3::Compilation::Compilation): (JSC::B3::Compilation::~Compilation): * b3/B3Compilation.h: Added. (JSC::B3::Compilation::code): * b3/B3ConstDoubleValue.h: (JSC::B3::ConstDoubleValue::accepts): Deleted. * b3/B3DataSection.cpp: Added. (JSC::B3::DataSection::DataSection): (JSC::B3::DataSection::~DataSection): (JSC::B3::DataSection::dump): * b3/B3DataSection.h: Added. (JSC::B3::DataSection::data): (JSC::B3::DataSection::size): * b3/B3Generate.cpp: (JSC::B3::generate): (JSC::B3::generateToAir): * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::imm): (JSC::B3::Air::LowerToAir::immOrTmp): (JSC::B3::Air::LowerToAir::fillStackmap): (JSC::B3::Air::LowerToAir::lower): (JSC::B3::Air::LowerToAir::immForMove): Deleted. (JSC::B3::Air::LowerToAir::immOrTmpForMove): Deleted. * b3/B3MoveConstants.cpp: Added. (JSC::B3::moveConstants): * b3/B3MoveConstants.h: Added. * b3/B3OpaqueByproduct.h: Added. (JSC::B3::OpaqueByproduct::OpaqueByproduct): (JSC::B3::OpaqueByproduct::~OpaqueByproduct): * b3/B3OpaqueByproducts.cpp: Added. (JSC::B3::OpaqueByproducts::OpaqueByproducts): (JSC::B3::OpaqueByproducts::~OpaqueByproducts): (JSC::B3::OpaqueByproducts::add): (JSC::B3::OpaqueByproducts::dump): * b3/B3OpaqueByproducts.h: Added. (JSC::B3::OpaqueByproducts::count): * b3/B3Opcode.h: (JSC::B3::constPtrOpcode): * b3/B3Procedure.cpp: (JSC::B3::Procedure::Procedure): (JSC::B3::Procedure::dump): (JSC::B3::Procedure::blocksInPreOrder): (JSC::B3::Procedure::deleteValue): (JSC::B3::Procedure::addDataSection): (JSC::B3::Procedure::addValueIndex): * b3/B3Procedure.h: (JSC::B3::Procedure::lastPhaseName): (JSC::B3::Procedure::byproducts): (JSC::B3::Procedure::takeByproducts): * b3/B3Type.h: * b3/B3Value.cpp: (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::performSubstitution): * b3/B3Value.h: * b3/B3ValueKey.cpp: Added. (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::type): (JSC::B3::ValueKey::childIndex): (JSC::B3::ValueKey::value): (JSC::B3::ValueKey::doubleValue): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::operator!=): (JSC::B3::ValueKey::hash): (JSC::B3::ValueKey::operator bool): (JSC::B3::ValueKey::canMaterialize): (JSC::B3::ValueKey::isHashTableDeletedValue): (JSC::B3::ValueKeyHash::hash): (JSC::B3::ValueKeyHash::equal): * b3/B3ValueKeyInlines.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::child): * b3/air/AirCode.cpp: (JSC::B3::Air::Code::Code): * b3/air/AirCode.h: (JSC::B3::Air::Code::proc): (JSC::B3::Air::Code::lastPhaseName): * b3/air/AirOpcode.opcodes: * b3/testb3.cpp: (JSC::B3::compile): (JSC::B3::invoke): (JSC::B3::compileAndRun): (JSC::B3::test42): (JSC::B3::testBranch): (JSC::B3::testBranchPtr): (JSC::B3::testDiamond): (JSC::B3::testBranchNotEqual): (JSC::B3::testBranchNotEqualCommute): (JSC::B3::testBranchNotEqualNotEqual): (JSC::B3::testBranchEqual): (JSC::B3::testBranchEqualEqual): (JSC::B3::testBranchEqualCommute): (JSC::B3::testBranchEqualEqual1): (JSC::B3::testBranchFold): (JSC::B3::testSimpleCheck): (JSC::B3::testCompare): (JSC::B3::testReturnDouble): (JSC::B3::run): Canonical link: https://commits.webkit.org/169260@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192183 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-11-10 00:01:24 +00:00
, m_type(type)
{
u.indices[0] = child->index();
}
B3 opcodes should leave room for flags https://bugs.webkit.org/show_bug.cgi?id=162692 Reviewed by Keith Miller. Source/JavaScriptCore: It used to be that the main thing that determined what a Value did was the opcode. The Opcode was how you knew what subclass of Value you had. The opcode told you what the Value actually did. This change replaces Opcode with Kind, which is a tuple of opcode and other stuff. Opcodes are great, and that's how most compilers work. But opcodes are one-dimensional. Here is how this manifests. Say you have an opcode, like Load. You will be happy if your IR has one Load opcode. But then, you might add Load8S/Load8Z/Load16S/Load16Z opcodes, as we have done in B3. B3 has one dimension of Load opcodes, which determines something like the C type of the load. But in the very near future, we will want to add two more dimensions to Loads: - A flag to say if the load traps. - A flag to say if the load has acquire semantics. Mapping these three dimensions (type, trap, acquire) onto the one-dimensional Opcode space would create mayham: Load8S, Load8STrap, Load8SAcquire, Load8STrapAcquire, Load8Z, Load8ZTrap, etc. This happens in other parts of the IR. For example, we have a dimension of arithmetic operations: add, sub, mul, div, mod, etc. Then we have the chill flag. But since opcodes are one-dimensional, that means having ChillDiv and ChillMod, and tons of places in the compiler that case on both Div and ChillDiv, or case on both Mod and ChillMod, since they are only interested in the kind of arithmetic being done and not the chillness. Though the examples all involve bits (chill or not, trapping or not, etc), I can imagine other properties that behave more like small enums, like if we fill out more memory ordering modes other than just "acquire? yes/no". There will eventually have to be something like a std::memory_order associated with memory accesses. One approach to this problem is to have a Value subclass that contains fields with the meta data. I don't like this for two reasons: - In bug 162688, I want to make trapping memory accesses have stackmaps. This means that a trapping memory access would have a different Value subclass than a non-trapping memory access. So, this meta-data needs to channel into ValueType::accepts(). Currently that takes Opcode and nothing else. - Compiler IRs are all about making common tasks easy. If it becomes commonplace for opcodes to require a custom Value subclass just for a bit then that's not very easy. This change addresses this problem by making the compiler pass around Kinds rather than Opcodes. A Kind contains an Opcode as well as any number of opcode-specific bits. This change demonstrates how Kind should be used by converting chillness to it. Kind has hasIsChill(), isChill(), and setIsChill() methods. hasIsChill() is true only for Div and Mod. setIsChill() asserts if !hasIsChill(). If you want to create a Chill Div, you say chill(Div). IR dumps will print it like this: Int32 @38 = Div<Chill>(@36, @37, DFG:@24, ControlDependent) Where "Div<Chill>" is how a Kind that hasExtraBits() dumps itself. If a Kind does not hasExtraBits() (the normal case) then it dumps like a normal Opcode (without the "<>"). I replaced many uses of Opcode with Kind. New code has to be mindful that Opcode may not be the right way to summarize what a value does, and so in many cases it's better to carry around a Kind instead - especially if you will use it to stamp out new Values. Opcode is no longer sufficient to perform a dynamic Value cast, since that code now uses Kind. ValueKey now wants a Kind instead of an Opcode. All Value constructors now take Kind instead of Opcode. But most opcodes don't get any extra Kind bits, and so the code that operates on those opcodes is largely unchanged. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * b3/B3ArgumentRegValue.h: * b3/B3CCallValue.h: * b3/B3CheckValue.cpp: (JSC::B3::CheckValue::convertToAdd): (JSC::B3::CheckValue::CheckValue): * b3/B3CheckValue.h: (JSC::B3::CheckValue::accepts): * b3/B3Const32Value.h: * b3/B3Const64Value.h: * b3/B3ConstDoubleValue.h: * b3/B3ConstFloatValue.h: * b3/B3FenceValue.h: * b3/B3Kind.cpp: Added. (JSC::B3::Kind::dump): * b3/B3Kind.h: Added. (JSC::B3::Kind::Kind): (JSC::B3::Kind::opcode): (JSC::B3::Kind::setOpcode): (JSC::B3::Kind::hasExtraBits): (JSC::B3::Kind::hasIsChill): (JSC::B3::Kind::isChill): (JSC::B3::Kind::setIsChill): (JSC::B3::Kind::operator==): (JSC::B3::Kind::operator!=): (JSC::B3::Kind::hash): (JSC::B3::Kind::isHashTableDeletedValue): (JSC::B3::chill): (JSC::B3::KindHash::hash): (JSC::B3::KindHash::equal): * b3/B3LowerMacros.cpp: * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::lower): * b3/B3MemoryValue.h: * b3/B3Opcode.cpp: (WTF::printInternal): * b3/B3Opcode.h: * b3/B3PatchpointValue.h: (JSC::B3::PatchpointValue::accepts): * b3/B3ReduceStrength.cpp: * b3/B3SlotBaseValue.h: * b3/B3StackmapValue.cpp: (JSC::B3::StackmapValue::StackmapValue): * b3/B3StackmapValue.h: * b3/B3SwitchValue.h: (JSC::B3::SwitchValue::accepts): * b3/B3UpsilonValue.h: * b3/B3Validate.cpp: * b3/B3Value.cpp: (JSC::B3::Value::dump): (JSC::B3::Value::deepDump): (JSC::B3::Value::invertedCompare): (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::typeFor): (JSC::B3::Value::badKind): (JSC::B3::Value::badOpcode): Deleted. * b3/B3Value.h: * b3/B3ValueInlines.h: (JSC::B3::Value::as): * b3/B3ValueKey.cpp: (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::kind): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::hash): * b3/B3ValueKeyInlines.h: (JSC::B3::ValueKey::ValueKey): * b3/B3VariableValue.cpp: (JSC::B3::VariableValue::VariableValue): * b3/B3VariableValue.h: * b3/testb3.cpp: (JSC::B3::testChillDiv): (JSC::B3::testChillDivTwice): (JSC::B3::testChillDiv64): (JSC::B3::testChillModArg): (JSC::B3::testChillModArgs): (JSC::B3::testChillModImms): (JSC::B3::testChillModArg32): (JSC::B3::testChillModArgs32): (JSC::B3::testChillModImms32): (JSC::B3::testSwitchChillDiv): (JSC::B3::testEntrySwitchWithCommonPaths): (JSC::B3::testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint): * ftl/FTLOutput.cpp: (JSC::FTL::Output::chillDiv): (JSC::FTL::Output::chillMod): Websites/webkit.org: Updated the documentation to talk about Kind and the isChill bit, and to remove ChillDiv/ChillMod. * docs/b3/intermediate-representation.html: Canonical link: https://commits.webkit.org/180677@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206595 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-09-29 18:44:53 +00:00
inline ValueKey::ValueKey(Kind kind, Type type, Value* left, Value* right)
: m_kind(kind)
B3 should be able to compile a program with a double constant https://bugs.webkit.org/show_bug.cgi?id=151002 Reviewed by Benjamin Poulain. This implements a bunch of annoying stuff that is necessary to support constants that need a data section, such as double constants on X86_64: - B3::Procedure can now tell you what to keep alive in addition to the MacroAssemblerCodeRef. We call this the B3::OpaqueByproducts. It's the client's responsibility to keep this alive after calling B3::generate(). - Added a new helper for compiling B3 code, called B3::Compilation. Constructing a Compilation runs the compiler. Then you can pass around a Compilation the way you would have passed around a MacroAssemblerCodeRef. - Added a constant motion phase, called moveConstants(). This does very simple constant hoisting/sinking: it makes sure that each constant is only materialized in one place in each basic block. It uses a DataSection, which is a kind of OpaqueByproduct, to store double constants. - The way I wanted to do constant motion is to basically track what constants are of interest and then recreate them as needed, so the original Values become irrelevant in the process. To do that, I needed an abstraction that is almost identical to the DFG PureValue abstraction that we use for CSE. So, I created such a thing, and called it ValueKey. It can be used to compare and hash pure Values, and to recreate them as needed. - Fixed the lowering's handling of constants so that we don't perturb the placement of the constant materializations. * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): (JSC::MacroAssemblerX86Common::moveZeroToDouble): (JSC::MacroAssemblerX86Common::branchDoubleNonZero): * b3/B3Common.h: (JSC::B3::isIdentical): (JSC::B3::isRepresentableAsImpl): * b3/B3Compilation.cpp: Added. (JSC::B3::Compilation::Compilation): (JSC::B3::Compilation::~Compilation): * b3/B3Compilation.h: Added. (JSC::B3::Compilation::code): * b3/B3ConstDoubleValue.h: (JSC::B3::ConstDoubleValue::accepts): Deleted. * b3/B3DataSection.cpp: Added. (JSC::B3::DataSection::DataSection): (JSC::B3::DataSection::~DataSection): (JSC::B3::DataSection::dump): * b3/B3DataSection.h: Added. (JSC::B3::DataSection::data): (JSC::B3::DataSection::size): * b3/B3Generate.cpp: (JSC::B3::generate): (JSC::B3::generateToAir): * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::imm): (JSC::B3::Air::LowerToAir::immOrTmp): (JSC::B3::Air::LowerToAir::fillStackmap): (JSC::B3::Air::LowerToAir::lower): (JSC::B3::Air::LowerToAir::immForMove): Deleted. (JSC::B3::Air::LowerToAir::immOrTmpForMove): Deleted. * b3/B3MoveConstants.cpp: Added. (JSC::B3::moveConstants): * b3/B3MoveConstants.h: Added. * b3/B3OpaqueByproduct.h: Added. (JSC::B3::OpaqueByproduct::OpaqueByproduct): (JSC::B3::OpaqueByproduct::~OpaqueByproduct): * b3/B3OpaqueByproducts.cpp: Added. (JSC::B3::OpaqueByproducts::OpaqueByproducts): (JSC::B3::OpaqueByproducts::~OpaqueByproducts): (JSC::B3::OpaqueByproducts::add): (JSC::B3::OpaqueByproducts::dump): * b3/B3OpaqueByproducts.h: Added. (JSC::B3::OpaqueByproducts::count): * b3/B3Opcode.h: (JSC::B3::constPtrOpcode): * b3/B3Procedure.cpp: (JSC::B3::Procedure::Procedure): (JSC::B3::Procedure::dump): (JSC::B3::Procedure::blocksInPreOrder): (JSC::B3::Procedure::deleteValue): (JSC::B3::Procedure::addDataSection): (JSC::B3::Procedure::addValueIndex): * b3/B3Procedure.h: (JSC::B3::Procedure::lastPhaseName): (JSC::B3::Procedure::byproducts): (JSC::B3::Procedure::takeByproducts): * b3/B3Type.h: * b3/B3Value.cpp: (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::performSubstitution): * b3/B3Value.h: * b3/B3ValueKey.cpp: Added. (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::type): (JSC::B3::ValueKey::childIndex): (JSC::B3::ValueKey::value): (JSC::B3::ValueKey::doubleValue): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::operator!=): (JSC::B3::ValueKey::hash): (JSC::B3::ValueKey::operator bool): (JSC::B3::ValueKey::canMaterialize): (JSC::B3::ValueKey::isHashTableDeletedValue): (JSC::B3::ValueKeyHash::hash): (JSC::B3::ValueKeyHash::equal): * b3/B3ValueKeyInlines.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::child): * b3/air/AirCode.cpp: (JSC::B3::Air::Code::Code): * b3/air/AirCode.h: (JSC::B3::Air::Code::proc): (JSC::B3::Air::Code::lastPhaseName): * b3/air/AirOpcode.opcodes: * b3/testb3.cpp: (JSC::B3::compile): (JSC::B3::invoke): (JSC::B3::compileAndRun): (JSC::B3::test42): (JSC::B3::testBranch): (JSC::B3::testBranchPtr): (JSC::B3::testDiamond): (JSC::B3::testBranchNotEqual): (JSC::B3::testBranchNotEqualCommute): (JSC::B3::testBranchNotEqualNotEqual): (JSC::B3::testBranchEqual): (JSC::B3::testBranchEqualEqual): (JSC::B3::testBranchEqualCommute): (JSC::B3::testBranchEqualEqual1): (JSC::B3::testBranchFold): (JSC::B3::testSimpleCheck): (JSC::B3::testCompare): (JSC::B3::testReturnDouble): (JSC::B3::run): Canonical link: https://commits.webkit.org/169260@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192183 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-11-10 00:01:24 +00:00
, m_type(type)
{
u.indices[0] = left->index();
u.indices[1] = right->index();
}
B3 opcodes should leave room for flags https://bugs.webkit.org/show_bug.cgi?id=162692 Reviewed by Keith Miller. Source/JavaScriptCore: It used to be that the main thing that determined what a Value did was the opcode. The Opcode was how you knew what subclass of Value you had. The opcode told you what the Value actually did. This change replaces Opcode with Kind, which is a tuple of opcode and other stuff. Opcodes are great, and that's how most compilers work. But opcodes are one-dimensional. Here is how this manifests. Say you have an opcode, like Load. You will be happy if your IR has one Load opcode. But then, you might add Load8S/Load8Z/Load16S/Load16Z opcodes, as we have done in B3. B3 has one dimension of Load opcodes, which determines something like the C type of the load. But in the very near future, we will want to add two more dimensions to Loads: - A flag to say if the load traps. - A flag to say if the load has acquire semantics. Mapping these three dimensions (type, trap, acquire) onto the one-dimensional Opcode space would create mayham: Load8S, Load8STrap, Load8SAcquire, Load8STrapAcquire, Load8Z, Load8ZTrap, etc. This happens in other parts of the IR. For example, we have a dimension of arithmetic operations: add, sub, mul, div, mod, etc. Then we have the chill flag. But since opcodes are one-dimensional, that means having ChillDiv and ChillMod, and tons of places in the compiler that case on both Div and ChillDiv, or case on both Mod and ChillMod, since they are only interested in the kind of arithmetic being done and not the chillness. Though the examples all involve bits (chill or not, trapping or not, etc), I can imagine other properties that behave more like small enums, like if we fill out more memory ordering modes other than just "acquire? yes/no". There will eventually have to be something like a std::memory_order associated with memory accesses. One approach to this problem is to have a Value subclass that contains fields with the meta data. I don't like this for two reasons: - In bug 162688, I want to make trapping memory accesses have stackmaps. This means that a trapping memory access would have a different Value subclass than a non-trapping memory access. So, this meta-data needs to channel into ValueType::accepts(). Currently that takes Opcode and nothing else. - Compiler IRs are all about making common tasks easy. If it becomes commonplace for opcodes to require a custom Value subclass just for a bit then that's not very easy. This change addresses this problem by making the compiler pass around Kinds rather than Opcodes. A Kind contains an Opcode as well as any number of opcode-specific bits. This change demonstrates how Kind should be used by converting chillness to it. Kind has hasIsChill(), isChill(), and setIsChill() methods. hasIsChill() is true only for Div and Mod. setIsChill() asserts if !hasIsChill(). If you want to create a Chill Div, you say chill(Div). IR dumps will print it like this: Int32 @38 = Div<Chill>(@36, @37, DFG:@24, ControlDependent) Where "Div<Chill>" is how a Kind that hasExtraBits() dumps itself. If a Kind does not hasExtraBits() (the normal case) then it dumps like a normal Opcode (without the "<>"). I replaced many uses of Opcode with Kind. New code has to be mindful that Opcode may not be the right way to summarize what a value does, and so in many cases it's better to carry around a Kind instead - especially if you will use it to stamp out new Values. Opcode is no longer sufficient to perform a dynamic Value cast, since that code now uses Kind. ValueKey now wants a Kind instead of an Opcode. All Value constructors now take Kind instead of Opcode. But most opcodes don't get any extra Kind bits, and so the code that operates on those opcodes is largely unchanged. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * b3/B3ArgumentRegValue.h: * b3/B3CCallValue.h: * b3/B3CheckValue.cpp: (JSC::B3::CheckValue::convertToAdd): (JSC::B3::CheckValue::CheckValue): * b3/B3CheckValue.h: (JSC::B3::CheckValue::accepts): * b3/B3Const32Value.h: * b3/B3Const64Value.h: * b3/B3ConstDoubleValue.h: * b3/B3ConstFloatValue.h: * b3/B3FenceValue.h: * b3/B3Kind.cpp: Added. (JSC::B3::Kind::dump): * b3/B3Kind.h: Added. (JSC::B3::Kind::Kind): (JSC::B3::Kind::opcode): (JSC::B3::Kind::setOpcode): (JSC::B3::Kind::hasExtraBits): (JSC::B3::Kind::hasIsChill): (JSC::B3::Kind::isChill): (JSC::B3::Kind::setIsChill): (JSC::B3::Kind::operator==): (JSC::B3::Kind::operator!=): (JSC::B3::Kind::hash): (JSC::B3::Kind::isHashTableDeletedValue): (JSC::B3::chill): (JSC::B3::KindHash::hash): (JSC::B3::KindHash::equal): * b3/B3LowerMacros.cpp: * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::lower): * b3/B3MemoryValue.h: * b3/B3Opcode.cpp: (WTF::printInternal): * b3/B3Opcode.h: * b3/B3PatchpointValue.h: (JSC::B3::PatchpointValue::accepts): * b3/B3ReduceStrength.cpp: * b3/B3SlotBaseValue.h: * b3/B3StackmapValue.cpp: (JSC::B3::StackmapValue::StackmapValue): * b3/B3StackmapValue.h: * b3/B3SwitchValue.h: (JSC::B3::SwitchValue::accepts): * b3/B3UpsilonValue.h: * b3/B3Validate.cpp: * b3/B3Value.cpp: (JSC::B3::Value::dump): (JSC::B3::Value::deepDump): (JSC::B3::Value::invertedCompare): (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::typeFor): (JSC::B3::Value::badKind): (JSC::B3::Value::badOpcode): Deleted. * b3/B3Value.h: * b3/B3ValueInlines.h: (JSC::B3::Value::as): * b3/B3ValueKey.cpp: (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::kind): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::hash): * b3/B3ValueKeyInlines.h: (JSC::B3::ValueKey::ValueKey): * b3/B3VariableValue.cpp: (JSC::B3::VariableValue::VariableValue): * b3/B3VariableValue.h: * b3/testb3.cpp: (JSC::B3::testChillDiv): (JSC::B3::testChillDivTwice): (JSC::B3::testChillDiv64): (JSC::B3::testChillModArg): (JSC::B3::testChillModArgs): (JSC::B3::testChillModImms): (JSC::B3::testChillModArg32): (JSC::B3::testChillModArgs32): (JSC::B3::testChillModImms32): (JSC::B3::testSwitchChillDiv): (JSC::B3::testEntrySwitchWithCommonPaths): (JSC::B3::testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint): * ftl/FTLOutput.cpp: (JSC::FTL::Output::chillDiv): (JSC::FTL::Output::chillMod): Websites/webkit.org: Updated the documentation to talk about Kind and the isChill bit, and to remove ChillDiv/ChillMod. * docs/b3/intermediate-representation.html: Canonical link: https://commits.webkit.org/180677@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206595 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-09-29 18:44:53 +00:00
inline ValueKey::ValueKey(Kind kind, Type type, Value* a, Value* b, Value* c)
: m_kind(kind)
B3 should have a Select opcode https://bugs.webkit.org/show_bug.cgi?id=150762 Reviewed by Benjamin Poulain. This cleans up our conditional move implementation - specifically so that it distinguishes between comparing the low 32 bits of a GPR and all bits of a GPR - and fixes bugs with operand ordering. It then adds a Select opcode to B3 and adds all of the strength reduction and lowering magic that it needs. Finally this change implements FTL::Output::select() in terms of B3::Select. This patch lets us run Kraken/imaging-gaussian-blur. Running that benchmark using FTL+B3 is a 17% speed-up. The compile times go down dramatically (by about 7x) and code quality stays about the same. * assembler/MacroAssembler.h: (JSC::MacroAssembler::moveDoubleConditionally32): (JSC::MacroAssembler::moveDoubleConditionally64): (JSC::MacroAssembler::moveDoubleConditionallyTest32): (JSC::MacroAssembler::moveDoubleConditionallyTest64): (JSC::MacroAssembler::moveDoubleConditionallyDouble): (JSC::MacroAssembler::lea): * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::move): (JSC::MacroAssemblerX86Common::moveConditionallyDouble): (JSC::MacroAssemblerX86Common::zeroExtend32ToPtr): (JSC::MacroAssemblerX86Common::moveConditionally32): (JSC::MacroAssemblerX86Common::moveConditionallyTest32): (JSC::MacroAssemblerX86Common::set32): (JSC::MacroAssemblerX86Common::cmov): (JSC::MacroAssemblerX86Common::moveConditionally): Deleted. (JSC::MacroAssemblerX86Common::moveConditionallyTest): Deleted. * assembler/MacroAssemblerX86_64.h: (JSC::MacroAssemblerX86_64::branchNeg64): (JSC::MacroAssemblerX86_64::moveConditionally64): (JSC::MacroAssemblerX86_64::moveConditionallyTest64): (JSC::MacroAssemblerX86_64::abortWithReason): * assembler/X86Assembler.h: (JSC::X86Assembler::cmovl_rr): (JSC::X86Assembler::cmovl_mr): (JSC::X86Assembler::cmovel_rr): (JSC::X86Assembler::cmovnel_rr): (JSC::X86Assembler::cmovpl_rr): (JSC::X86Assembler::cmovnpl_rr): (JSC::X86Assembler::cmovq_rr): (JSC::X86Assembler::cmovq_mr): (JSC::X86Assembler::cmoveq_rr): (JSC::X86Assembler::cmovneq_rr): (JSC::X86Assembler::cmovpq_rr): (JSC::X86Assembler::cmovnpq_rr): * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::createCompare): (JSC::B3::Air::LowerToAir::createSelect): (JSC::B3::Air::LowerToAir::marshallCCallArgument): (JSC::B3::Air::LowerToAir::lower): * b3/B3MoveConstants.cpp: * b3/B3Opcode.cpp: (WTF::printInternal): * b3/B3Opcode.h: * b3/B3ReduceStrength.cpp: * b3/B3Validate.cpp: * b3/B3Value.cpp: (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::checkOpcode): (JSC::B3::Value::typeFor): * b3/B3Value.h: * b3/B3ValueKey.cpp: (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::hash): (JSC::B3::ValueKey::operator bool): * b3/B3ValueKeyInlines.h: (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::child): * b3/air/AirOpcode.opcodes: * b3/testb3.cpp: (JSC::B3::testTruncSExt32): (JSC::B3::testBasicSelect): (JSC::B3::testSelectTest): (JSC::B3::testSelectCompareDouble): (JSC::B3::testSelectDouble): (JSC::B3::testSelectDoubleTest): (JSC::B3::testSelectDoubleCompareDouble): (JSC::B3::zero): (JSC::B3::run): * ftl/FTLB3Output.h: (JSC::FTL::Output::testIsZeroPtr): (JSC::FTL::Output::testNonZeroPtr): (JSC::FTL::Output::select): (JSC::FTL::Output::extractValue): (JSC::FTL::Output::fence): Canonical link: https://commits.webkit.org/169661@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192699 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-11-20 22:31:19 +00:00
, m_type(type)
{
u.indices[0] = a->index();
u.indices[1] = b->index();
u.indices[2] = c->index();
}
B3 should be able to compile a program with a double constant https://bugs.webkit.org/show_bug.cgi?id=151002 Reviewed by Benjamin Poulain. This implements a bunch of annoying stuff that is necessary to support constants that need a data section, such as double constants on X86_64: - B3::Procedure can now tell you what to keep alive in addition to the MacroAssemblerCodeRef. We call this the B3::OpaqueByproducts. It's the client's responsibility to keep this alive after calling B3::generate(). - Added a new helper for compiling B3 code, called B3::Compilation. Constructing a Compilation runs the compiler. Then you can pass around a Compilation the way you would have passed around a MacroAssemblerCodeRef. - Added a constant motion phase, called moveConstants(). This does very simple constant hoisting/sinking: it makes sure that each constant is only materialized in one place in each basic block. It uses a DataSection, which is a kind of OpaqueByproduct, to store double constants. - The way I wanted to do constant motion is to basically track what constants are of interest and then recreate them as needed, so the original Values become irrelevant in the process. To do that, I needed an abstraction that is almost identical to the DFG PureValue abstraction that we use for CSE. So, I created such a thing, and called it ValueKey. It can be used to compare and hash pure Values, and to recreate them as needed. - Fixed the lowering's handling of constants so that we don't perturb the placement of the constant materializations. * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): (JSC::MacroAssemblerX86Common::moveZeroToDouble): (JSC::MacroAssemblerX86Common::branchDoubleNonZero): * b3/B3Common.h: (JSC::B3::isIdentical): (JSC::B3::isRepresentableAsImpl): * b3/B3Compilation.cpp: Added. (JSC::B3::Compilation::Compilation): (JSC::B3::Compilation::~Compilation): * b3/B3Compilation.h: Added. (JSC::B3::Compilation::code): * b3/B3ConstDoubleValue.h: (JSC::B3::ConstDoubleValue::accepts): Deleted. * b3/B3DataSection.cpp: Added. (JSC::B3::DataSection::DataSection): (JSC::B3::DataSection::~DataSection): (JSC::B3::DataSection::dump): * b3/B3DataSection.h: Added. (JSC::B3::DataSection::data): (JSC::B3::DataSection::size): * b3/B3Generate.cpp: (JSC::B3::generate): (JSC::B3::generateToAir): * b3/B3LowerToAir.cpp: (JSC::B3::Air::LowerToAir::imm): (JSC::B3::Air::LowerToAir::immOrTmp): (JSC::B3::Air::LowerToAir::fillStackmap): (JSC::B3::Air::LowerToAir::lower): (JSC::B3::Air::LowerToAir::immForMove): Deleted. (JSC::B3::Air::LowerToAir::immOrTmpForMove): Deleted. * b3/B3MoveConstants.cpp: Added. (JSC::B3::moveConstants): * b3/B3MoveConstants.h: Added. * b3/B3OpaqueByproduct.h: Added. (JSC::B3::OpaqueByproduct::OpaqueByproduct): (JSC::B3::OpaqueByproduct::~OpaqueByproduct): * b3/B3OpaqueByproducts.cpp: Added. (JSC::B3::OpaqueByproducts::OpaqueByproducts): (JSC::B3::OpaqueByproducts::~OpaqueByproducts): (JSC::B3::OpaqueByproducts::add): (JSC::B3::OpaqueByproducts::dump): * b3/B3OpaqueByproducts.h: Added. (JSC::B3::OpaqueByproducts::count): * b3/B3Opcode.h: (JSC::B3::constPtrOpcode): * b3/B3Procedure.cpp: (JSC::B3::Procedure::Procedure): (JSC::B3::Procedure::dump): (JSC::B3::Procedure::blocksInPreOrder): (JSC::B3::Procedure::deleteValue): (JSC::B3::Procedure::addDataSection): (JSC::B3::Procedure::addValueIndex): * b3/B3Procedure.h: (JSC::B3::Procedure::lastPhaseName): (JSC::B3::Procedure::byproducts): (JSC::B3::Procedure::takeByproducts): * b3/B3Type.h: * b3/B3Value.cpp: (JSC::B3::Value::effects): (JSC::B3::Value::key): (JSC::B3::Value::performSubstitution): * b3/B3Value.h: * b3/B3ValueKey.cpp: Added. (JSC::B3::ValueKey::dump): (JSC::B3::ValueKey::materialize): * b3/B3ValueKey.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::opcode): (JSC::B3::ValueKey::type): (JSC::B3::ValueKey::childIndex): (JSC::B3::ValueKey::value): (JSC::B3::ValueKey::doubleValue): (JSC::B3::ValueKey::operator==): (JSC::B3::ValueKey::operator!=): (JSC::B3::ValueKey::hash): (JSC::B3::ValueKey::operator bool): (JSC::B3::ValueKey::canMaterialize): (JSC::B3::ValueKey::isHashTableDeletedValue): (JSC::B3::ValueKeyHash::hash): (JSC::B3::ValueKeyHash::equal): * b3/B3ValueKeyInlines.h: Added. (JSC::B3::ValueKey::ValueKey): (JSC::B3::ValueKey::child): * b3/air/AirCode.cpp: (JSC::B3::Air::Code::Code): * b3/air/AirCode.h: (JSC::B3::Air::Code::proc): (JSC::B3::Air::Code::lastPhaseName): * b3/air/AirOpcode.opcodes: * b3/testb3.cpp: (JSC::B3::compile): (JSC::B3::invoke): (JSC::B3::compileAndRun): (JSC::B3::test42): (JSC::B3::testBranch): (JSC::B3::testBranchPtr): (JSC::B3::testDiamond): (JSC::B3::testBranchNotEqual): (JSC::B3::testBranchNotEqualCommute): (JSC::B3::testBranchNotEqualNotEqual): (JSC::B3::testBranchEqual): (JSC::B3::testBranchEqualEqual): (JSC::B3::testBranchEqualCommute): (JSC::B3::testBranchEqualEqual1): (JSC::B3::testBranchFold): (JSC::B3::testSimpleCheck): (JSC::B3::testCompare): (JSC::B3::testReturnDouble): (JSC::B3::run): Canonical link: https://commits.webkit.org/169260@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192183 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-11-10 00:01:24 +00:00
inline Value* ValueKey::child(Procedure& proc, unsigned index) const
{
return proc.values()[index];
}
} } // namespace JSC::B3
#endif // ENABLE(B3_JIT)