B3 opcodes should leave room for flags
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Sep 2016 18:44:53 +0000 (18:44 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Sep 2016 18:44:53 +0000 (18:44 +0000)
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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206595 268f45cc-cd09-0410-ab3c-d52691b4dbfc

39 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/b3/B3ArgumentRegValue.h
Source/JavaScriptCore/b3/B3CCallValue.h
Source/JavaScriptCore/b3/B3CheckValue.cpp
Source/JavaScriptCore/b3/B3CheckValue.h
Source/JavaScriptCore/b3/B3Const32Value.h
Source/JavaScriptCore/b3/B3Const64Value.h
Source/JavaScriptCore/b3/B3ConstDoubleValue.h
Source/JavaScriptCore/b3/B3ConstFloatValue.h
Source/JavaScriptCore/b3/B3FenceValue.h
Source/JavaScriptCore/b3/B3Kind.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/B3Kind.h [new file with mode: 0644]
Source/JavaScriptCore/b3/B3LowerMacros.cpp
Source/JavaScriptCore/b3/B3LowerToAir.cpp
Source/JavaScriptCore/b3/B3MemoryValue.h
Source/JavaScriptCore/b3/B3Opcode.cpp
Source/JavaScriptCore/b3/B3Opcode.h
Source/JavaScriptCore/b3/B3PatchpointValue.h
Source/JavaScriptCore/b3/B3ReduceStrength.cpp
Source/JavaScriptCore/b3/B3SlotBaseValue.h
Source/JavaScriptCore/b3/B3StackmapValue.cpp
Source/JavaScriptCore/b3/B3StackmapValue.h
Source/JavaScriptCore/b3/B3SwitchValue.h
Source/JavaScriptCore/b3/B3UpsilonValue.h
Source/JavaScriptCore/b3/B3Validate.cpp
Source/JavaScriptCore/b3/B3Value.cpp
Source/JavaScriptCore/b3/B3Value.h
Source/JavaScriptCore/b3/B3ValueInlines.h
Source/JavaScriptCore/b3/B3ValueKey.cpp
Source/JavaScriptCore/b3/B3ValueKey.h
Source/JavaScriptCore/b3/B3ValueKeyInlines.h
Source/JavaScriptCore/b3/B3VariableValue.cpp
Source/JavaScriptCore/b3/B3VariableValue.h
Source/JavaScriptCore/b3/testb3.cpp
Source/JavaScriptCore/ftl/FTLOutput.cpp
Websites/webkit.org/ChangeLog
Websites/webkit.org/docs/b3/intermediate-representation.html

index a98d864..b74dffd 100644 (file)
@@ -133,6 +133,7 @@ set(JavaScriptCore_SOURCES
     b3/B3HeapRange.cpp
     b3/B3InferSwitches.cpp
     b3/B3InsertionSet.cpp
+    b3/B3Kind.cpp
     b3/B3LegalizeMemoryOffsets.cpp
     b3/B3LowerMacros.cpp
     b3/B3LowerMacrosAfterOptimizations.cpp
index 68f5152..1a72773 100644 (file)
@@ -1,3 +1,162 @@
+2016-09-28  Filip Pizlo  <fpizlo@apple.com>
+
+        B3 opcodes should leave room for flags
+        https://bugs.webkit.org/show_bug.cgi?id=162692
+
+        Reviewed by Keith Miller.
+
+        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):
+
 2016-09-29  Saam Barati  <sbarati@apple.com>
 
         We don't properly propagate non-simple-parameter-list when parsing a setter
index 29fec2c..3986a20 100644 (file)
                0FDB2CEA174896C7007B3C1B /* ConcurrentJITLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; };
                0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; };
+               0FDF67D21D9C6D27001B9825 /* B3Kind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDF67D11D9C6086001B9825 /* B3Kind.h */; };
+               0FDF67D31D9C6D2A001B9825 /* B3Kind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D01D9C6086001B9825 /* B3Kind.cpp */; };
                0FDF70851D3F2C2200927449 /* AirLowerEntrySwitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF70831D3F2C1F00927449 /* AirLowerEntrySwitch.cpp */; };
                0FDF70861D3F2C2500927449 /* AirLowerEntrySwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDF70841D3F2C1F00927449 /* AirLowerEntrySwitch.h */; };
                0FE050141AA9091100D33B33 /* ArgumentsMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConcurrentJITLock.h; sourceTree = "<group>"; };
                0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = "<group>"; };
                0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; };
+               0FDF67D01D9C6086001B9825 /* B3Kind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3Kind.cpp; path = b3/B3Kind.cpp; sourceTree = "<group>"; };
+               0FDF67D11D9C6086001B9825 /* B3Kind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3Kind.h; path = b3/B3Kind.h; sourceTree = "<group>"; };
                0FDF70831D3F2C1F00927449 /* AirLowerEntrySwitch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirLowerEntrySwitch.cpp; path = b3/air/AirLowerEntrySwitch.cpp; sourceTree = "<group>"; };
                0FDF70841D3F2C1F00927449 /* AirLowerEntrySwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirLowerEntrySwitch.h; path = b3/air/AirLowerEntrySwitch.h; sourceTree = "<group>"; };
                0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgumentsMode.h; sourceTree = "<group>"; };
                                0FEC85B41BE1462F0080FF74 /* B3InsertionSet.cpp */,
                                0FEC85B51BE1462F0080FF74 /* B3InsertionSet.h */,
                                0FEC85B61BE1462F0080FF74 /* B3InsertionSetInlines.h */,
+                               0FDF67D01D9C6086001B9825 /* B3Kind.cpp */,
+                               0FDF67D11D9C6086001B9825 /* B3Kind.h */,
                                436E54511C468E5F00B5AF73 /* B3LegalizeMemoryOffsets.cpp */,
                                436E54521C468E5F00B5AF73 /* B3LegalizeMemoryOffsets.h */,
                                0F338E191BF286EA0013C88F /* B3LowerMacros.cpp */,
                                0F64EAF31C4ECD0600621E9B /* AirArgInlines.h in Headers */,
                                A5EA710519F6DE740098F5EC /* generate_objc_configuration_header.py in Headers */,
                                DC69B99D1D15F914002E3C00 /* B3InferSwitches.h in Headers */,
+                               0FDF67D21D9C6D27001B9825 /* B3Kind.h in Headers */,
                                A5EA710619F6DE760098F5EC /* generate_objc_configuration_implementation.py in Headers */,
                                0F7C39FF1C90C55B00480151 /* DFGOpInfo.h in Headers */,
                                A5EA710719F6DE780098F5EC /* generate_objc_protocol_type_conversions_header.py in Headers */,
                                0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */,
                                0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */,
                                0F338E121BF0276C0013C88F /* B3OpaqueByproducts.cpp in Sources */,
+                               0FDF67D31D9C6D2A001B9825 /* B3Kind.cpp in Sources */,
                                0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */,
                                C2C0F7CD17BBFC5B00464FE4 /* DFGDesiredTransitions.cpp in Sources */,
                                0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */,
index b424149..55b365f 100644 (file)
@@ -34,7 +34,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE ArgumentRegValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == ArgumentReg; }
+    static bool accepts(Kind kind) { return kind == ArgumentReg; }
     
     ~ArgumentRegValue();
 
index 9a8b9d1..44ec349 100644 (file)
@@ -34,7 +34,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE CCallValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == CCall; }
+    static bool accepts(Kind kind) { return kind == CCall; }
 
     ~CCallValue();
 
index b8b27cc..79b6c6e 100644 (file)
@@ -37,7 +37,7 @@ CheckValue::~CheckValue()
 void CheckValue::convertToAdd()
 {
     RELEASE_ASSERT(opcode() == CheckAdd || opcode() == CheckSub || opcode() == CheckMul);
-    m_opcode = CheckAdd;
+    m_kind = CheckAdd;
 }
 
 Value* CheckValue::cloneImpl() const
@@ -46,21 +46,21 @@ Value* CheckValue::cloneImpl() const
 }
 
 // Use this form for CheckAdd, CheckSub, and CheckMul.
-CheckValue::CheckValue(Opcode opcode, Origin origin, Value* left, Value* right)
-    : StackmapValue(CheckedOpcode, opcode, left->type(), origin)
+CheckValue::CheckValue(Kind kind, Origin origin, Value* left, Value* right)
+    : StackmapValue(CheckedOpcode, kind, left->type(), origin)
 {
     ASSERT(B3::isInt(type()));
     ASSERT(left->type() == right->type());
-    ASSERT(opcode == CheckAdd || opcode == CheckSub || opcode == CheckMul);
+    ASSERT(kind == CheckAdd || kind == CheckSub || kind == CheckMul);
     append(ConstrainedValue(left, ValueRep::WarmAny));
     append(ConstrainedValue(right, ValueRep::WarmAny));
 }
 
 // Use this form for Check.
-CheckValue::CheckValue(Opcode opcode, Origin origin, Value* predicate)
-    : StackmapValue(CheckedOpcode, opcode, Void, origin)
+CheckValue::CheckValue(Kind kind, Origin origin, Value* predicate)
+    : StackmapValue(CheckedOpcode, kind, Void, origin)
 {
-    ASSERT(opcode == Check);
+    ASSERT(kind == Check);
     append(ConstrainedValue(predicate, ValueRep::WarmAny));
 }
 
index ab1b7ed..e3d94ba 100644 (file)
@@ -33,9 +33,9 @@ namespace JSC { namespace B3 {
 
 class CheckValue : public StackmapValue {
 public:
-    static bool accepts(Opcode opcode)
+    static bool accepts(Kind kind)
     {
-        switch (opcode) {
+        switch (kind.opcode()) {
         case CheckAdd:
         case CheckSub:
         case CheckMul:
@@ -57,10 +57,10 @@ private:
     friend class Procedure;
 
     // Use this form for CheckAdd, CheckSub, and CheckMul.
-    JS_EXPORT_PRIVATE CheckValue(Opcode, Origin, Value* left, Value* right);
+    JS_EXPORT_PRIVATE CheckValue(Kind, Origin, Value* left, Value* right);
 
     // Use this form for Check.
-    JS_EXPORT_PRIVATE CheckValue(Opcode, Origin, Value* predicate);
+    JS_EXPORT_PRIVATE CheckValue(Kind, Origin, Value* predicate);
 };
 
 } } // namespace JSC::B3
index 48e5737..6766750 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE Const32Value : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == Const32; }
+    static bool accepts(Kind kind) { return kind == Const32; }
     
     ~Const32Value();
     
index a4ce316..f4258d6 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE Const64Value : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == Const64; }
+    static bool accepts(Kind kind) { return kind == Const64; }
     
     ~Const64Value();
     
index a418ad2..75976f3 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE ConstDoubleValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == ConstDouble; }
+    static bool accepts(Kind kind) { return kind == ConstDouble; }
     
     ~ConstDoubleValue();
     
index 8027565..1974f8c 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE ConstFloatValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == ConstFloat; }
+    static bool accepts(Kind kind) { return kind == ConstFloat; }
 
     ~ConstFloatValue();
 
index 53e187c..d147052 100644 (file)
@@ -34,7 +34,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE FenceValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == Fence; }
+    static bool accepts(Kind kind) { return kind == Fence; }
     
     ~FenceValue();
     
diff --git a/Source/JavaScriptCore/b3/B3Kind.cpp b/Source/JavaScriptCore/b3/B3Kind.cpp
new file mode 100644 (file)
index 0000000..c04a298
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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 "B3Kind.h"
+
+#if ENABLE(B3_JIT)
+
+#include <wtf/CommaPrinter.h>
+
+namespace JSC { namespace B3 {
+
+void Kind::dump(PrintStream& out) const
+{
+    out.print(m_opcode);
+    if (!hasExtraBits())
+        return;
+    
+    CommaPrinter comma;
+    out.print("<");
+    if (isChill())
+        out.print(comma, "Chill");
+    out.print(">");
+}
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
diff --git a/Source/JavaScriptCore/b3/B3Kind.h b/Source/JavaScriptCore/b3/B3Kind.h
new file mode 100644 (file)
index 0000000..5aedac8
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 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. 
+ */
+
+#ifndef B3Kind_h
+#define B3Kind_h
+
+#if ENABLE(B3_JIT)
+
+#include "B3Opcode.h"
+#include <wtf/HashTable.h>
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace B3 {
+
+// A Kind is a terse summary of what a Value does. There is a fixed number of possible
+// Kinds. Kind is a tuple of Opcode (see B3Opcode.h) and some extra bits. Most opcodes don't
+// get any extra bits, and those bits must remain zero if the Kind's opcode field is set to
+// one of those opcodes. The purpose of Kind is to be like an opcode in other IRs, but to
+// be multidimensional. For example, a Load has many dimensions of customization that we may
+// eventually implement. A Load can have different alignments, alignment failure modes,
+// temporality modes, trapping modes, ordering modes, etc. It's fine to put such flags into
+// subclasses of Value, but in some cases that would be overkill, particularly since if you
+// did that for a pure value then you'd also have to thread it through ValueKey. It's much
+// easier to put it in Kind, and then your extra bit will get carried around by everyone who
+// knows how to carry around Kinds. Most importantly, putting flags into Kind allows you to
+// use them as part of B3::Value's dynamic cast facility. For example we could have a
+// trapping Load that uses a Value subclass that has a stackmap while non-trapping Loads
+// continue to use the normal MemoryValue.
+//
+// Note that any code in the compiler that transcribes IR (like a strength reduction that
+// replaces an Add with a different Add, or even with a different opcode entirely) will
+// probably drop unknown bits by default. This is definitely not correct for many bits (like
+// isChill for Div/Mod and all of the envisioned Load/Store flags), so if you add a new bit
+// you will probably have to audit the compiler to make sure that phases that transcribe
+// your opcode do the right thing with your bit.
+
+class Kind {
+public:
+    Kind(Opcode opcode)
+        : m_opcode(opcode)
+    {
+        u.bits = 0;
+    }
+    
+    Kind()
+        : Kind(Oops)
+    {
+    }
+    
+    Opcode opcode() const { return m_opcode; }
+    void setOpcode(Opcode opcode) { m_opcode = opcode; }
+    
+    bool hasExtraBits() const { return !!u.bits; }
+    
+    // Chill bit. This applies to division-based arithmetic ops, which may trap on some
+    // platforms or exhibit bizarre behavior when passed certain inputs. The non-chill
+    // version will behave as unpredictably as it wants. For example, it's legal to
+    // constant-fold Div(x, 0) to any value or to replace it with any effectful operation.
+    // But when it's chill, that means that the semantics when it would have trapped are
+    // the JS semantics. For example, Div<Chill>(@a, @b) means:
+    //
+    //     ((a | 0) / (b | 0)) | 0
+    //
+    // And Mod<Chill>(a, b) means:
+    //
+    //     ((a | 0) % (b | 0)) | 0
+    //
+    // Note that Div<Chill> matches exactly how ARM handles integer division.
+    bool hasIsChill() const
+    {
+        switch (m_opcode) {
+        case Div:
+        case Mod:
+            return true;
+        default:
+            return false;
+        }
+    }
+    bool isChill() const
+    {
+        return hasIsChill() && u.isChill;
+    }
+    void setIsChill(bool isChill)
+    {
+        ASSERT(hasIsChill());
+        u.isChill = isChill;
+    }
+    
+    // Rules for adding new properties:
+    // - Put the accessors here.
+    // - hasBlah() should check if the opcode allows for your property.
+    // - blah() returns a default value if !hasBlah()
+    // - setBlah() asserts if !hasBlah()
+    // - Try not to increase the size of Kind too much. But it wouldn't be the end of the
+    //   world if it bloated to 64 bits.
+    
+    bool operator==(const Kind& other) const
+    {
+        return m_opcode == other.m_opcode
+            && u.bits == other.u.bits;
+    }
+    
+    bool operator!=(const Kind& other) const
+    {
+        return !(*this == other);
+    }
+    
+    void dump(PrintStream&) const;
+    
+    unsigned hash() const
+    {
+        // It's almost certainly more important that this hash function is cheap to compute than
+        // anything else. We can live with some kind hash collisions.
+        return m_opcode + u.bits * 111;
+    }
+    
+    Kind(WTF::HashTableDeletedValueType)
+        : m_opcode(Oops)
+    {
+        u.bits = 1;
+    }
+    
+    bool isHashTableDeletedValue() const
+    {
+        return *this == Kind(WTF::HashTableDeletedValue);
+    }
+    
+private:
+    Opcode m_opcode;
+    union {
+        bool isChill;
+        uint16_t bits;
+    } u;
+};
+
+// For every flag 'foo' you add, it's customary to create a Kind B3::foo(Kind) function that makes
+// a kind with the flag set. For example, for chill, this lets us say:
+//
+//     block->appendNew<Value>(m_proc, chill(Mod), Origin(), a, b);
+//
+// That looks pretty slick. Let's keep it that way.
+
+inline Kind chill(Kind kind)
+{
+    kind.setIsChill(true);
+    return kind;
+}
+
+struct KindHash {
+    static unsigned hash(const Kind& key) { return key.hash(); }
+    static bool equal(const Kind& a, const Kind& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} } // namespace JSC::B3
+
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::B3::Kind> {
+    typedef JSC::B3::KindHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::B3::Kind> : public SimpleClassHashTraits<JSC::B3::Kind> {
+    static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3Kind_h
+
index fa6de93..d5ba0f4 100644 (file)
@@ -83,6 +83,41 @@ private:
             m_origin = m_value->origin();
             switch (m_value->opcode()) {
             case Mod: {
+                if (m_value->isChill()) {
+                    if (isARM64()) {
+                        BasicBlock* before = m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
+                        BasicBlock* zeroDenCase = m_blockInsertionSet.insertBefore(m_block);
+                        BasicBlock* normalModCase = m_blockInsertionSet.insertBefore(m_block);
+
+                        before->replaceLastWithNew<Value>(m_proc, Branch, m_origin, m_value->child(1));
+                        before->setSuccessors(
+                            FrequentedBlock(normalModCase, FrequencyClass::Normal),
+                            FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
+
+                        Value* divResult = normalModCase->appendNew<Value>(m_proc, chill(Div), m_origin, m_value->child(0), m_value->child(1));
+                        Value* multipliedBack = normalModCase->appendNew<Value>(m_proc, Mul, m_origin, divResult, m_value->child(1));
+                        Value* result = normalModCase->appendNew<Value>(m_proc, Sub, m_origin, m_value->child(0), multipliedBack);
+                        UpsilonValue* normalResult = normalModCase->appendNew<UpsilonValue>(m_proc, m_origin, result);
+                        normalModCase->appendNew<Value>(m_proc, Jump, m_origin);
+                        normalModCase->setSuccessors(FrequentedBlock(m_block));
+
+                        UpsilonValue* zeroResult = zeroDenCase->appendNew<UpsilonValue>(
+                            m_proc, m_origin,
+                            zeroDenCase->appendIntConstant(m_proc, m_value, 0));
+                        zeroDenCase->appendNew<Value>(m_proc, Jump, m_origin);
+                        zeroDenCase->setSuccessors(FrequentedBlock(m_block));
+
+                        Value* phi = m_insertionSet.insert<Value>(m_index, Phi, m_value->type(), m_origin);
+                        normalResult->setPhi(phi);
+                        zeroResult->setPhi(phi);
+                        m_value->replaceWithIdentity(phi);
+                        before->updatePredecessorsAfter();
+                        m_changed = true;
+                    } else
+                        makeDivisionChill(Mod);
+                    break;
+                }
+                
                 double (*fmodDouble)(double, double) = fmod;
                 if (m_value->type() == Double) {
                     Value* functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, fmodDouble);
@@ -106,7 +141,7 @@ private:
                     m_value->replaceWithIdentity(result);
                     m_changed = true;
                 } else if (isARM64()) {
-                    Value* divResult = m_insertionSet.insert<Value>(m_index, ChillDiv, m_origin, m_value->child(0), m_value->child(1));
+                    Value* divResult = m_insertionSet.insert<Value>(m_index, chill(Div), m_origin, m_value->child(0), m_value->child(1));
                     Value* multipliedBack = m_insertionSet.insert<Value>(m_index, Mul, m_origin, divResult, m_value->child(1));
                     Value* result = m_insertionSet.insert<Value>(m_index, Sub, m_origin, m_value->child(0), multipliedBack);
                     m_value->replaceWithIdentity(result);
@@ -114,43 +149,9 @@ private:
                 }
                 break;
             }
-            case ChillDiv: {
-                makeDivisionChill(Div);
-                break;
-            }
-
-            case ChillMod: {
-                if (isARM64()) {
-                    BasicBlock* before = m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
-                    BasicBlock* zeroDenCase = m_blockInsertionSet.insertBefore(m_block);
-                    BasicBlock* normalModCase = m_blockInsertionSet.insertBefore(m_block);
-
-                    before->replaceLastWithNew<Value>(m_proc, Branch, m_origin, m_value->child(1));
-                    before->setSuccessors(
-                        FrequentedBlock(normalModCase, FrequencyClass::Normal),
-                        FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
-
-                    Value* divResult = normalModCase->appendNew<Value>(m_proc, ChillDiv, m_origin, m_value->child(0), m_value->child(1));
-                    Value* multipliedBack = normalModCase->appendNew<Value>(m_proc, Mul, m_origin, divResult, m_value->child(1));
-                    Value* result = normalModCase->appendNew<Value>(m_proc, Sub, m_origin, m_value->child(0), multipliedBack);
-                    UpsilonValue* normalResult = normalModCase->appendNew<UpsilonValue>(m_proc, m_origin, result);
-                    normalModCase->appendNew<Value>(m_proc, Jump, m_origin);
-                    normalModCase->setSuccessors(FrequentedBlock(m_block));
-
-                    UpsilonValue* zeroResult = zeroDenCase->appendNew<UpsilonValue>(
-                        m_proc, m_origin,
-                        zeroDenCase->appendIntConstant(m_proc, m_value, 0));
-                    zeroDenCase->appendNew<Value>(m_proc, Jump, m_origin);
-                    zeroDenCase->setSuccessors(FrequentedBlock(m_block));
-
-                    Value* phi = m_insertionSet.insert<Value>(m_index, Phi, m_value->type(), m_origin);
-                    normalResult->setPhi(phi);
-                    zeroResult->setPhi(phi);
-                    m_value->replaceWithIdentity(phi);
-                    before->updatePredecessorsAfter();
-                    m_changed = true;
-                } else
-                    makeDivisionChill(Mod);
+            case Div: {
+                if (m_value->isChill())
+                    makeDivisionChill(Div);
                 break;
             }
 
@@ -188,7 +189,7 @@ private:
         if (isARM64())
             return;
 
-        // We implement "res = ChillDiv/ChillMod(num, den)" as follows:
+        // We implement "res = Div<Chill>/Mod<Chill>(num, den)" as follows:
         //
         //     if (den + 1 <=_unsigned 1) {
         //         if (!den) {
index 7599af1..ffd6691 100644 (file)
@@ -1846,10 +1846,9 @@ private:
             return;
         }
 
-        case ChillDiv:
-            RELEASE_ASSERT(isARM64());
-            FALLTHROUGH;
         case Div: {
+            if (m_value->isChill())
+                RELEASE_ASSERT(isARM64());
 #if CPU(X86) || CPU(X86_64)
             if (isInt(m_value->type())) {
                 lowerX86Div();
@@ -1865,6 +1864,7 @@ private:
 
         case Mod: {
             RELEASE_ASSERT(isX86());
+            RELEASE_ASSERT(!m_value->isChill());
 #if CPU(X86) || CPU(X86_64)
             lowerX86Div();
             append(Move, Tmp(X86Registers::edx), tmp(m_value));
index 7621dbf..9a0504f 100644 (file)
@@ -37,9 +37,9 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE MemoryValue : public Value {
 public:
-    static bool accepts(Opcode opcode)
+    static bool accepts(Kind kind)
     {
-        switch (opcode) {
+        switch (kind.opcode()) {
         case Load8Z:
         case Load8S:
         case Load16Z:
@@ -54,9 +54,9 @@ public:
         }
     }
 
-    static bool isStore(Opcode opcode)
+    static bool isStore(Kind kind)
     {
-        switch (opcode) {
+        switch (kind.opcode()) {
         case Store8:
         case Store16:
         case Store:
@@ -66,9 +66,9 @@ public:
         }
     }
 
-    static bool isLoad(Opcode opcode)
+    static bool isLoad(Kind kind)
     {
-        return accepts(opcode) && !isStore(opcode);
+        return accepts(kind) && !isStore(kind);
     }
 
     ~MemoryValue();
@@ -94,13 +94,13 @@ private:
 
     // Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
     // describes the returned type).
-    MemoryValue(Opcode opcode, Type type, Origin origin, Value* pointer, int32_t offset = 0)
-        : Value(CheckedOpcode, opcode, type, origin, pointer)
+    MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, int32_t offset = 0)
+        : Value(CheckedOpcode, kind, type, origin, pointer)
         , m_offset(offset)
         , m_range(HeapRange::top())
     {
         if (!ASSERT_DISABLED) {
-            switch (opcode) {
+            switch (kind.opcode()) {
             case Load:
                 break;
             case Load8Z:
@@ -121,19 +121,19 @@ private:
     }
 
     // Use this form for loads where the return type is implied.
-    MemoryValue(Opcode opcode, Origin origin, Value* pointer, int32_t offset = 0)
-        : MemoryValue(opcode, Int32, origin, pointer, offset)
+    MemoryValue(Kind kind, Origin origin, Value* pointer, int32_t offset = 0)
+        : MemoryValue(kind, Int32, origin, pointer, offset)
     {
     }
 
     // Use this form for stores.
-    MemoryValue(Opcode opcode, Origin origin, Value* value, Value* pointer, int32_t offset = 0)
-        : Value(CheckedOpcode, opcode, Void, origin, value, pointer)
+    MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, int32_t offset = 0)
+        : Value(CheckedOpcode, kind, Void, origin, value, pointer)
         , m_offset(offset)
         , m_range(HeapRange::top())
     {
         if (!ASSERT_DISABLED) {
-            switch (opcode) {
+            switch (kind.opcode()) {
             case Store8:
             case Store16:
             case Store:
index 6498096..f03a94c 100644 (file)
@@ -128,12 +128,6 @@ void printInternal(PrintStream& out, Opcode opcode)
     case Neg:
         out.print("Neg");
         return;
-    case ChillDiv:
-        out.print("ChillDiv");
-        return;
-    case ChillMod:
-        out.print("ChillMod");
-        return;
     case BitAnd:
         out.print("BitAnd");
         return;
index 160e83d..c977347 100644 (file)
@@ -33,6 +33,9 @@
 
 namespace JSC { namespace B3 {
 
+// Warning: In B3, an Opcode is just one part of a Kind. Kind is used the way that an opcode
+// would be used in simple IRs. See B3Kind.h.
+
 enum Opcode : int16_t {
     // A no-op that returns Void, useful for when you want to remove a value.
     Nop,
@@ -83,8 +86,6 @@ enum Opcode : int16_t {
     Neg,
 
     // Integer math.
-    ChillDiv, // doesn't trap ever, behaves like JS (x/y)|0.
-    ChillMod, // doesn't trap ever, behaves like JS (x%y)|0.
     BitAnd,
     BitOr,
     BitXor,
index 843706c..3378dc4 100644 (file)
@@ -37,7 +37,7 @@ class PatchpointValue : public StackmapValue {
 public:
     typedef StackmapValue Base;
     
-    static bool accepts(Opcode opcode) { return opcode == Patchpoint; }
+    static bool accepts(Kind kind) { return kind == Patchpoint; }
 
     ~PatchpointValue();
 
index 0bd1ea0..180bf44 100644 (file)
@@ -648,10 +648,9 @@ private:
             break;
 
         case Div:
-        case ChillDiv:
             // Turn this: Div(constant1, constant2)
             // Into this: constant1 / constant2
-            // Note that this uses ChillDiv semantics. That's fine, because the rules for Div
+            // Note that this uses Div<Chill> semantics. That's fine, because the rules for Div
             // are strictly weaker: it has corner cases where it's allowed to do anything it
             // likes.
             if (replaceWithNewValue(m_value->child(0)->divConstant(m_proc, m_value->child(1))))
@@ -737,10 +736,9 @@ private:
             break;
 
         case Mod:
-        case ChillMod:
             // Turn this: Mod(constant1, constant2)
             // Into this: constant1 / constant2
-            // Note that this uses ChillMod semantics.
+            // Note that this uses Mod<Chill> semantics.
             if (replaceWithNewValue(m_value->child(0)->modConstant(m_proc, m_value->child(1))))
                 break;
 
@@ -774,19 +772,8 @@ private:
                     //                = -2^31 - -2^31
                     //                = 0
 
-                    Opcode divOpcode;
-                    switch (m_value->opcode()) {
-                    case Mod:
-                        divOpcode = Div;
-                        break;
-                    case ChillMod:
-                        divOpcode = ChillDiv;
-                        break;
-                    default:
-                        divOpcode = Oops;
-                        RELEASE_ASSERT_NOT_REACHED();
-                        break;
-                    }
+                    Kind divKind = Div;
+                    divKind.setIsChill(m_value->isChill());
 
                     replaceWithIdentity(
                         m_insertionSet.insert<Value>(
@@ -795,7 +782,7 @@ private:
                             m_insertionSet.insert<Value>(
                                 m_index, Mul, m_value->origin(),
                                 m_insertionSet.insert<Value>(
-                                    m_index, divOpcode, m_value->origin(),
+                                    m_index, divKind, m_value->origin(),
                                     m_value->child(0), m_value->child(1)),
                                 m_value->child(1))));
                     break;
index c2f54a4..19392ea 100644 (file)
@@ -35,7 +35,7 @@ class StackSlot;
 
 class JS_EXPORT_PRIVATE SlotBaseValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == SlotBase; }
+    static bool accepts(Kind kind) { return kind == SlotBase; }
 
     ~SlotBaseValue();
 
index b822ea9..9b0db2f 100644 (file)
@@ -83,10 +83,10 @@ void StackmapValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
         ", lateClobbered = ", m_lateClobbered, ", usedRegisters = ", m_usedRegisters);
 }
 
-StackmapValue::StackmapValue(CheckedOpcodeTag, Opcode opcode, Type type, Origin origin)
-    : Value(CheckedOpcode, opcode, type, origin)
+StackmapValue::StackmapValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
+    : Value(CheckedOpcode, kind, type, origin)
 {
-    ASSERT(accepts(opcode));
+    ASSERT(accepts(kind));
 }
 
 } } // namespace JSC::B3
index d83b386..66fc644 100644 (file)
@@ -43,10 +43,10 @@ typedef SharedTask<StackmapGeneratorFunction> StackmapGenerator;
 
 class JS_EXPORT_PRIVATE StackmapValue : public Value {
 public:
-    static bool accepts(Opcode opcode)
+    static bool accepts(Kind kind)
     {
         // This needs to include opcodes of all subclasses.
-        switch (opcode) {
+        switch (kind.opcode()) {
         case CheckAdd:
         case CheckSub:
         case CheckMul:
@@ -288,7 +288,7 @@ protected:
     void dumpChildren(CommaPrinter&, PrintStream&) const override;
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    StackmapValue(CheckedOpcodeTag, Opcode, Type, Origin);
+    StackmapValue(CheckedOpcodeTag, Kind, Type, Origin);
 
 private:
     friend class CheckSpecial;
index d03c638..a1c27cd 100644 (file)
@@ -35,7 +35,7 @@ namespace JSC { namespace B3 {
 
 class SwitchValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == Switch; }
+    static bool accepts(Kind kind) { return kind == Switch; }
 
     ~SwitchValue();
 
index d6a2a8f..4c479e4 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC { namespace B3 {
 
 class JS_EXPORT_PRIVATE UpsilonValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == Upsilon; }
+    static bool accepts(Kind kind) { return kind == Upsilon; }
 
     ~UpsilonValue();
 
index 8bc59a0..c1deb69 100644 (file)
@@ -131,44 +131,54 @@ public:
             switch (value->opcode()) {
             case Nop:
             case Fence:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 break;
             case Identity:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
                 VALIDATE(value->type() != Void, ("At ", *value));
                 break;
             case Const32:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
                 break;
             case Const64:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Int64, ("At ", *value));
                 break;
             case ConstDouble:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Double, ("At ", *value));
                 break;
             case ConstFloat:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Float, ("At ", *value));
                 break;
             case Set:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == value->as<VariableValue>()->variable()->type(), ("At ", *value));
                 break;
             case Get:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == value->as<VariableValue>()->variable()->type(), ("At ", *value));
                 break;
             case SlotBase:
             case FramePointer:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == pointerType(), ("At ", *value));
                 break;
             case ArgumentReg:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(
                     (value->as<ArgumentRegValue>()->argumentReg().isGPR() ? pointerType() : Double)
@@ -181,19 +191,31 @@ public:
             case Mod:
             case BitAnd:
             case BitXor:
+                switch (value->opcode()) {
+                case Div:
+                case Mod:
+                    if (value->isChill()) {
+                        VALIDATE(value->opcode() == Div || value->opcode() == Mod, ("At ", *value));
+                        VALIDATE(isInt(value->type()), ("At ", *value));
+                    }
+                    break;
+                default:
+                    VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
+                    break;
+                }
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
                 VALIDATE(value->type() == value->child(1)->type(), ("At ", *value));
                 VALIDATE(value->type() != Void, ("At ", *value));
                 break;
             case Neg:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
                 VALIDATE(value->type() != Void, ("At ", *value));
                 break;
-            case ChillDiv:
-            case ChillMod:
             case BitOr:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
                 VALIDATE(value->type() == value->child(1)->type(), ("At ", *value));
@@ -202,12 +224,14 @@ public:
             case Shl:
             case SShr:
             case ZShr:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
                 VALIDATE(value->child(1)->type() == Int32, ("At ", *value));
                 VALIDATE(isInt(value->type()), ("At ", *value));
                 break;
             case BitwiseCast:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->type() != value->child(0)->type(), ("At ", *value));
                 VALIDATE(
@@ -219,22 +243,26 @@ public:
                 break;
             case SExt8:
             case SExt16:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == Int32, ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
                 break;
             case SExt32:
             case ZExt32:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == Int32, ("At ", *value));
                 VALIDATE(value->type() == Int64, ("At ", *value));
                 break;
             case Clz:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(isInt(value->type()), ("At ", *value));
                 break;
             case Trunc:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == Int64, ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
@@ -243,26 +271,31 @@ public:
             case Ceil:
             case Floor:
             case Sqrt:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(isFloat(value->child(0)->type()), ("At ", *value));
                 VALIDATE(isFloat(value->type()), ("At ", *value));
                 break;
             case IToD:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == Double, ("At ", *value));
                 break;
             case IToF:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == Float, ("At ", *value));
                 break;
             case FloatToDouble:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == Float, ("At ", *value));
                 VALIDATE(value->type() == Double, ("At ", *value));
                 break;
             case DoubleToFloat:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == Double, ("At ", *value));
                 VALIDATE(value->type() == Float, ("At ", *value));
@@ -273,6 +306,7 @@ public:
             case GreaterThan:
             case LessEqual:
             case GreaterEqual:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->child(0)->type() == value->child(1)->type(), ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
@@ -281,18 +315,21 @@ public:
             case Below:
             case AboveEqual:
             case BelowEqual:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->child(0)->type() == value->child(1)->type(), ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
                 break;
             case EqualOrUnordered:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->child(0)->type() == value->child(1)->type(), ("At ", *value));
                 VALIDATE(isFloat(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
                 break;
             case Select:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 3, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == value->child(1)->type(), ("At ", *value));
@@ -302,12 +339,14 @@ public:
             case Load8S:
             case Load16Z:
             case Load16S:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == pointerType(), ("At ", *value));
                 VALIDATE(value->type() == Int32, ("At ", *value));
                 validateStackAccess(value);
                 break;
             case Load:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == pointerType(), ("At ", *value));
                 VALIDATE(value->type() != Void, ("At ", *value));
@@ -315,6 +354,7 @@ public:
                 break;
             case Store8:
             case Store16:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->child(0)->type() == Int32, ("At ", *value));
                 VALIDATE(value->child(1)->type() == pointerType(), ("At ", *value));
@@ -322,16 +362,19 @@ public:
                 validateStackAccess(value);
                 break;
             case Store:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 2, ("At ", *value));
                 VALIDATE(value->child(1)->type() == pointerType(), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 validateStackAccess(value);
                 break;
             case CCall:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() >= 1, ("At ", *value));
                 VALIDATE(value->child(0)->type() == pointerType(), ("At ", *value));
                 break;
             case Patchpoint:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 if (value->type() == Void)
                     VALIDATE(value->as<PatchpointValue>()->resultConstraint == ValueRep::WarmAny, ("At ", *value));
                 else {
@@ -354,6 +397,7 @@ public:
             case CheckAdd:
             case CheckSub:
             case CheckMul:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() >= 2, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(isInt(value->child(1)->type()), ("At ", *value));
@@ -362,12 +406,14 @@ public:
                 validateStackmap(value);
                 break;
             case Check:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() >= 1, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->as<StackmapValue>()->constrainedChild(0).rep() == ValueRep::WarmAny, ("At ", *value));
                 validateStackmap(value);
                 break;
             case Upsilon:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(value->as<UpsilonValue>()->phi(), ("At ", *value));
                 VALIDATE(value->as<UpsilonValue>()->phi()->opcode() == Phi, ("At ", *value));
@@ -375,31 +421,37 @@ public:
                 VALIDATE(valueInProc.contains(value->as<UpsilonValue>()->phi()), ("At ", *value));
                 break;
             case Phi:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() != Void, ("At ", *value));
                 break;
             case Jump:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 VALIDATE(valueOwner.get(value)->numSuccessors() == 1, ("At ", *value));
                 break;
             case Oops:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 VALIDATE(!valueOwner.get(value)->numSuccessors(), ("At ", *value));
                 break;
             case Return:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() <= 1, ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 VALIDATE(!valueOwner.get(value)->numSuccessors(), ("At ", *value));
                 break;
             case Branch:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 VALIDATE(valueOwner.get(value)->numSuccessors() == 2, ("At ", *value));
                 break;
             case Switch: {
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
                 VALIDATE(isInt(value->child(0)->type()), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
@@ -417,6 +469,7 @@ public:
                 break;
             }
             case EntrySwitch:
+                VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 VALIDATE(valueOwner.get(value)->numSuccessors() == m_procedure.numEntrypoints(), ("At ", *value));
index dc860ce..f067ab5 100644 (file)
@@ -175,7 +175,7 @@ void Value::dump(PrintStream& out) const
 {
     bool isConstant = false;
 
-    switch (m_opcode) {
+    switch (opcode()) {
     case Const32:
         out.print("$", asInt32(), "(");
         isConstant = true;
@@ -215,7 +215,7 @@ void Value::dumpChildren(CommaPrinter& comma, PrintStream& out) const
 
 void Value::deepDump(const Procedure* proc, PrintStream& out) const
 {
-    out.print(m_type, " ", dumpPrefix, m_index, " = ", m_opcode);
+    out.print(m_type, " ", dumpPrefix, m_index, " = ", m_kind);
 
     out.print("(");
     CommaPrinter comma;
@@ -437,8 +437,10 @@ Value* Value::invertedCompare(Procedure& proc) const
 {
     if (!numChildren())
         return nullptr;
-    if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type()))
+    if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type())) {
+        ASSERT(!kind().hasExtraBits());
         return proc.add<Value>(*invertedOpcode, type(), origin(), children());
+    }
     return nullptr;
 }
 
@@ -532,8 +534,6 @@ Effects Value::effects() const
     case Sub:
     case Mul:
     case Neg:
-    case ChillDiv:
-    case ChillMod:
     case BitAnd:
     case BitOr:
     case BitXor:
@@ -642,7 +642,7 @@ ValueKey Value::key() const
 {
     switch (opcode()) {
     case FramePointer:
-        return ValueKey(opcode(), type());
+        return ValueKey(kind(), type());
     case Identity:
     case Abs:
     case Ceil:
@@ -661,14 +661,12 @@ ValueKey Value::key() const
     case Check:
     case BitwiseCast:
     case Neg:
-        return ValueKey(opcode(), type(), child(0));
+        return ValueKey(kind(), type(), child(0));
     case Add:
     case Sub:
     case Mul:
     case Div:
     case Mod:
-    case ChillDiv:
-    case ChillMod:
     case BitAnd:
     case BitOr:
     case BitXor:
@@ -687,9 +685,9 @@ ValueKey Value::key() const
     case CheckAdd:
     case CheckSub:
     case CheckMul:
-        return ValueKey(opcode(), type(), child(0), child(1));
+        return ValueKey(kind(), type(), child(0), child(1));
     case Select:
-        return ValueKey(opcode(), type(), child(0), child(1), child(2));
+        return ValueKey(kind(), type(), child(0), child(1), child(2));
     case Const32:
         return ValueKey(Const32, type(), static_cast<int64_t>(asInt32()));
     case Const64:
@@ -738,9 +736,9 @@ void Value::dumpMeta(CommaPrinter&, PrintStream&) const
 {
 }
 
-Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
+Type Value::typeFor(Kind kind, Value* firstChild, Value* secondChild)
 {
-    switch (opcode) {
+    switch (kind.opcode()) {
     case Identity:
     case Add:
     case Sub:
@@ -748,8 +746,6 @@ Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
     case Div:
     case Mod:
     case Neg:
-    case ChillDiv:
-    case ChillMod:
     case BitAnd:
     case BitOr:
     case BitXor:
@@ -820,9 +816,9 @@ Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
     }
 }
 
-void Value::badOpcode(Opcode opcode, unsigned numArgs)
+void Value::badKind(Kind kind, unsigned numArgs)
 {
-    dataLog("Bad opcode ", opcode, " with ", numArgs, " args.\n");
+    dataLog("Bad kind ", kind, " with ", numArgs, " args.\n");
     RELEASE_ASSERT_NOT_REACHED();
 }
 
index d078ca3..a391bc0 100644 (file)
@@ -30,7 +30,7 @@
 #include "AirArg.h"
 #include "B3Effects.h"
 #include "B3FrequentedBlock.h"
-#include "B3Opcode.h"
+#include "B3Kind.h"
 #include "B3Origin.h"
 #include "B3SparseCollection.h"
 #include "B3Type.h"
@@ -54,15 +54,21 @@ public:
 
     static const char* const dumpPrefix;
 
-    static bool accepts(Opcode) { return true; }
+    static bool accepts(Kind) { return true; }
 
     virtual ~Value();
 
     unsigned index() const { return m_index; }
     
-    // Note that the opcode is immutable, except for replacing values with:
+    // Note that the kind is immutable, except for replacing values with:
     // Identity, Nop, Oops, Jump, and Phi. See below for replaceWithXXX() methods.
-    Opcode opcode() const { return m_opcode; }
+    Kind kind() const { return m_kind; }
+    
+    Opcode opcode() const { return kind().opcode(); }
+    
+    // It's good practice to mirror Kind methods here, so you can say value->isBlah()
+    // instead of value->kind().isBlah().
+    bool isChill() const { return kind().isChill(); }
 
     Origin origin() const { return m_origin; }
     void setOrigin(Origin origin) { m_origin = origin; }
@@ -131,8 +137,8 @@ public:
     //     things
     // }
     //
-    // This will return null if this opcode() != ArgumentReg. This works because this returns nullptr
-    // if T::accepts(opcode()) returns false.
+    // This will return null if this kind() != ArgumentReg. This works because this returns nullptr
+    // if T::accepts(kind()) returns false.
     template<typename T>
     T* as();
     template<typename T>
@@ -141,7 +147,7 @@ public:
     // What follows are a bunch of helpers for inspecting and modifying values. Note that we have a
     // bunch of different idioms for implementing such helpers. You can use virtual methods, and
     // override from the various Value subclasses. You can put the method inside Value and make it
-    // non-virtual, and the implementation can switch on opcode. The method could be inline or not.
+    // non-virtual, and the implementation can switch on kind. The method could be inline or not.
     // If a method is specific to some Value subclass, you could put it in the subclass, or you could
     // put it on Value anyway. It's fine to pick whatever feels right, and we shouldn't restrict
     // ourselves to any particular idiom.
@@ -158,8 +164,8 @@ public:
     virtual Value* checkSubConstant(Procedure&, const Value* other) const;
     virtual Value* checkMulConstant(Procedure&, const Value* other) const;
     virtual Value* checkNegConstant(Procedure&) const;
-    virtual Value* divConstant(Procedure&, const Value* other) const; // This chooses ChillDiv semantics for integers.
-    virtual Value* modConstant(Procedure&, const Value* other) const; // This chooses ChillMod semantics.
+    virtual Value* divConstant(Procedure&, const Value* other) const; // This chooses Div<Chill> semantics for integers.
+    virtual Value* modConstant(Procedure&, const Value* other) const; // This chooses Mod<Chill> semantics.
     virtual Value* bitAndConstant(Procedure&, const Value* other) const;
     virtual Value* bitOrConstant(Procedure&, const Value* other) const;
     virtual Value* bitXorConstant(Procedure&, const Value* other) const;
@@ -273,10 +279,10 @@ private:
     friend class Procedure;
     friend class SparseCollection<Value>;
 
-    // Checks that this opcode is valid for use with B3::Value.
-    ALWAYS_INLINE static void checkOpcode(Opcode opcode, unsigned numArgs)
+    // Checks that this kind is valid for use with B3::Value.
+    ALWAYS_INLINE static void checkKind(Kind kind, unsigned numArgs)
     {
-        switch (opcode) {
+        switch (kind.opcode()) {
         case FramePointer:
         case Nop:
         case Phi:
@@ -284,11 +290,11 @@ private:
         case Oops:
         case EntrySwitch:
             if (UNLIKELY(numArgs))
-                badOpcode(opcode, numArgs);
+                badKind(kind, numArgs);
             break;
         case Return:
             if (UNLIKELY(numArgs > 1))
-                badOpcode(opcode, numArgs);
+                badKind(kind, numArgs);
             break;
         case Identity:
         case Neg:
@@ -309,15 +315,13 @@ private:
         case BitwiseCast:
         case Branch:
             if (UNLIKELY(numArgs != 1))
-                badOpcode(opcode, numArgs);
+                badKind(kind, numArgs);
             break;
         case Add:
         case Sub:
         case Mul:
         case Div:
         case Mod:
-        case ChillDiv:
-        case ChillMod:
         case BitAnd:
         case BitOr:
         case BitXor:
@@ -336,14 +340,14 @@ private:
         case BelowEqual:
         case EqualOrUnordered:
             if (UNLIKELY(numArgs != 2))
-                badOpcode(opcode, numArgs);
+                badKind(kind, numArgs);
             break;
         case Select:
             if (UNLIKELY(numArgs != 3))
-                badOpcode(opcode, numArgs);
+                badKind(kind, numArgs);
             break;
         default:
-            badOpcode(opcode, numArgs);
+            badKind(kind, numArgs);
             break;
         }
     }
@@ -357,56 +361,56 @@ protected:
     // Instantiate values via Procedure.
     // This form requires specifying the type explicitly:
     template<typename... Arguments>
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Type type, Origin origin, Value* firstChild, Arguments... arguments)
-        : m_opcode(opcode)
+    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Value* firstChild, Arguments... arguments)
+        : m_kind(kind)
         , m_type(type)
         , m_origin(origin)
         , m_children{ firstChild, arguments... }
     {
     }
     // This form is for specifying the type explicitly when the opcode has no children:
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Type type, Origin origin)
-        : m_opcode(opcode)
+    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
+        : m_kind(kind)
         , m_type(type)
         , m_origin(origin)
     {
     }
     // This form is for those opcodes that can infer their type from the opcode and first child:
     template<typename... Arguments>
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild)
-        : m_opcode(opcode)
-        , m_type(typeFor(opcode, firstChild))
+    explicit Value(CheckedOpcodeTag, Kind kind, Origin origin, Value* firstChild)
+        : m_kind(kind)
+        , m_type(typeFor(kind, firstChild))
         , m_origin(origin)
         , m_children{ firstChild }
     {
     }
     // This form is for those opcodes that can infer their type from the opcode and first and second child:
     template<typename... Arguments>
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
-        : m_opcode(opcode)
-        , m_type(typeFor(opcode, firstChild, secondChild))
+    explicit Value(CheckedOpcodeTag, Kind kind, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
+        : m_kind(kind)
+        , m_type(typeFor(kind, firstChild, secondChild))
         , m_origin(origin)
         , m_children{ firstChild, secondChild, arguments... }
     {
     }
     // This form is for those opcodes that can infer their type from the opcode alone, and that don't
     // take any arguments:
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Origin origin)
-        : m_opcode(opcode)
-        , m_type(typeFor(opcode, nullptr))
+    explicit Value(CheckedOpcodeTag, Kind kind, Origin origin)
+        : m_kind(kind)
+        , m_type(typeFor(kind, nullptr))
         , m_origin(origin)
     {
     }
     // Use this form for varargs.
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Type type, Origin origin, const AdjacencyList& children)
-        : m_opcode(opcode)
+    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, const AdjacencyList& children)
+        : m_kind(kind)
         , m_type(type)
         , m_origin(origin)
         , m_children(children)
     {
     }
-    explicit Value(CheckedOpcodeTag, Opcode opcode, Type type, Origin origin, AdjacencyList&& children)
-        : m_opcode(opcode)
+    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, AdjacencyList&& children)
+        : m_kind(kind)
         , m_type(type)
         , m_origin(origin)
         , m_children(WTFMove(children))
@@ -416,52 +420,52 @@ protected:
     // This is the constructor you end up actually calling, if you're instantiating Value
     // directly.
     template<typename... Arguments>
-        explicit Value(Opcode opcode, Type type, Origin origin)
-        : Value(CheckedOpcode, opcode, type, origin)
+        explicit Value(Kind kind, Type type, Origin origin)
+        : Value(CheckedOpcode, kind, type, origin)
     {
-        checkOpcode(opcode, 0);
+        checkKind(kind, 0);
     }
     template<typename... Arguments>
-        explicit Value(Opcode opcode, Type type, Origin origin, Value* firstChild, Arguments&&... arguments)
-        : Value(CheckedOpcode, opcode, type, origin, firstChild, std::forward<Arguments>(arguments)...)
+        explicit Value(Kind kind, Type type, Origin origin, Value* firstChild, Arguments&&... arguments)
+        : Value(CheckedOpcode, kind, type, origin, firstChild, std::forward<Arguments>(arguments)...)
     {
-        checkOpcode(opcode, 1 + sizeof...(arguments));
+        checkKind(kind, 1 + sizeof...(arguments));
     }
     template<typename... Arguments>
-        explicit Value(Opcode opcode, Type type, Origin origin, const AdjacencyList& children)
-        : Value(CheckedOpcode, opcode, type, origin, children)
+        explicit Value(Kind kind, Type type, Origin origin, const AdjacencyList& children)
+        : Value(CheckedOpcode, kind, type, origin, children)
     {
-        checkOpcode(opcode, children.size());
+        checkKind(kind, children.size());
     }
     template<typename... Arguments>
-        explicit Value(Opcode opcode, Type type, Origin origin, AdjacencyList&& children)
-        : Value(CheckedOpcode, opcode, type, origin, WTFMove(children))
+        explicit Value(Kind kind, Type type, Origin origin, AdjacencyList&& children)
+        : Value(CheckedOpcode, kind, type, origin, WTFMove(children))
     {
-        checkOpcode(opcode, m_children.size());
+        checkKind(kind, m_children.size());
     }
     template<typename... Arguments>
-        explicit Value(Opcode opcode, Origin origin, Arguments&&... arguments)
-        : Value(CheckedOpcode, opcode, origin, std::forward<Arguments>(arguments)...)
+        explicit Value(Kind kind, Origin origin, Arguments&&... arguments)
+        : Value(CheckedOpcode, kind, origin, std::forward<Arguments>(arguments)...)
     {
-        checkOpcode(opcode, sizeof...(arguments));
+        checkKind(kind, sizeof...(arguments));
     }
 
 private:
-    friend class CheckValue; // CheckValue::convertToAdd() modifies m_opcode.
+    friend class CheckValue; // CheckValue::convertToAdd() modifies m_kind.
     
-    static Type typeFor(Opcode, Value* firstChild, Value* secondChild = nullptr);
+    static Type typeFor(Kind, Value* firstChild, Value* secondChild = nullptr);
 
     // This group of fields is arranged to fit in 64 bits.
 protected:
     unsigned m_index { UINT_MAX };
 private:
-    Opcode m_opcode;
+    Kind m_kind;
     Type m_type;
     
     Origin m_origin;
     AdjacencyList m_children;
 
-    JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void badOpcode(Opcode, unsigned);
+    JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void badKind(Kind, unsigned);
 
 public:
     BasicBlock* owner { nullptr }; // computed by Procedure::resetValueOwners().
index df10605..97d82b9 100644 (file)
@@ -57,7 +57,7 @@ void Value::replaceWithBottom(const BottomProvider& bottomProvider)
 template<typename T>
 inline T* Value::as()
 {
-    if (T::accepts(opcode()))
+    if (T::accepts(kind()))
         return static_cast<T*>(this);
     return nullptr;
 }
index e7f3f64..bc098c0 100644 (file)
@@ -51,14 +51,14 @@ ValueKey ValueKey::intConstant(Type type, int64_t value)
 
 void ValueKey::dump(PrintStream& out) const
 {
-    out.print(m_type, " ", m_opcode, "(", u.indices[0], ", ", u.indices[1], ", ", u.indices[2], ")");
+    out.print(m_type, " ", m_kind, "(", u.indices[0], ", ", u.indices[1], ", ", u.indices[2], ")");
 }
 
 Value* ValueKey::materialize(Procedure& proc, Origin origin) const
 {
     switch (opcode()) {
     case FramePointer:
-        return proc.add<Value>(opcode(), type(), origin);
+        return proc.add<Value>(kind(), type(), origin);
     case Identity:
     case Sqrt:
     case SExt8:
@@ -72,11 +72,10 @@ Value* ValueKey::materialize(Procedure& proc, Origin origin) const
     case FloatToDouble:
     case DoubleToFloat:
     case Check:
-        return proc.add<Value>(opcode(), type(), origin, child(proc, 0));
+        return proc.add<Value>(kind(), type(), origin, child(proc, 0));
     case Add:
     case Sub:
     case Mul:
-    case ChillDiv:
     case Mod:
     case BitAnd:
     case BitOr:
@@ -93,9 +92,9 @@ Value* ValueKey::materialize(Procedure& proc, Origin origin) const
     case AboveEqual:
     case BelowEqual:
     case Div:
-        return proc.add<Value>(opcode(), type(), origin, child(proc, 0), child(proc, 1));
+        return proc.add<Value>(kind(), type(), origin, child(proc, 0), child(proc, 1));
     case Select:
-        return proc.add<Value>(opcode(), type(), origin, child(proc, 0), child(proc, 1), child(proc, 2));
+        return proc.add<Value>(kind(), type(), origin, child(proc, 0), child(proc, 1), child(proc, 2));
     case Const32:
         return proc.add<Const32Value>(origin, static_cast<int32_t>(value()));
     case Const64:
index 7ea4f2c..18b092c 100644 (file)
@@ -28,7 +28,7 @@
 #if ENABLE(B3_JIT)
 
 #include "B3HeapRange.h"
-#include "B3Opcode.h"
+#include "B3Kind.h"
 #include "B3Origin.h"
 #include "B3Type.h"
 #include <wtf/HashTable.h>
@@ -50,34 +50,34 @@ public:
     {
     }
 
-    ValueKey(Opcode opcode, Type type)
-        : m_opcode(opcode)
+    ValueKey(Kind kind, Type type)
+        : m_kind(kind)
         , m_type(type)
     {
     }
 
-    ValueKey(Opcode, Type, Value* child);
+    ValueKey(Kind, Type, Value* child);
 
-    ValueKey(Opcode, Type, Value* left, Value* right);
+    ValueKey(Kind, Type, Value* left, Value* right);
 
-    ValueKey(Opcode, Type, Value* a, Value* b, Value* c);
+    ValueKey(Kind, Type, Value* a, Value* b, Value* c);
 
-    ValueKey(Opcode opcode, Type type, int64_t value)
-        : m_opcode(opcode)
+    ValueKey(Kind kind, Type type, int64_t value)
+        : m_kind(kind)
         , m_type(type)
     {
         u.value = value;
     }
 
-    ValueKey(Opcode opcode, Type type, double value)
-        : m_opcode(opcode)
+    ValueKey(Kind kind, Type type, double value)
+        : m_kind(kind)
         , m_type(type)
     {
         u.doubleValue = value;
     }
 
-    ValueKey(Opcode opcode, Type type, float value)
-        : m_opcode(opcode)
+    ValueKey(Kind kind, Type type, float value)
+        : m_kind(kind)
         , m_type(type)
     {
         u.floatValue = value;
@@ -85,7 +85,8 @@ public:
 
     static ValueKey intConstant(Type type, int64_t value);
 
-    Opcode opcode() const { return m_opcode; }
+    Kind kind() const { return m_kind; }
+    Opcode opcode() const { return kind().opcode(); }
     Type type() const { return m_type; }
     unsigned childIndex(unsigned index) const { return u.indices[index]; }
     Value* child(Procedure&, unsigned index) const;
@@ -95,7 +96,7 @@ public:
 
     bool operator==(const ValueKey& other) const
     {
-        return m_opcode == other.m_opcode
+        return m_kind == other.m_kind
             && m_type == other.m_type
             && u == other.u;
     }
@@ -107,7 +108,7 @@ public:
 
     unsigned hash() const
     {
-        return m_opcode + m_type + WTF::IntHash<int32_t>::hash(u.indices[0]) + u.indices[1] + u.indices[2];
+        return m_kind.hash() + m_type + WTF::IntHash<int32_t>::hash(u.indices[0]) + u.indices[1] + u.indices[2];
     }
 
     explicit operator bool() const { return *this != ValueKey(); }
@@ -149,7 +150,7 @@ public:
     }
         
 private:
-    Opcode m_opcode { Oops };
+    Kind m_kind;
     Type m_type { Void };
     union U {
         unsigned indices[3];
index bcb446a..14158d5 100644 (file)
 
 namespace JSC { namespace B3 {
 
-inline ValueKey::ValueKey(Opcode opcode, Type type, Value* child)
-    : m_opcode(opcode)
+inline ValueKey::ValueKey(Kind kind, Type type, Value* child)
+    : m_kind(kind)
     , m_type(type)
 {
     u.indices[0] = child->index();
 }
 
-inline ValueKey::ValueKey(Opcode opcode, Type type, Value* left, Value* right)
-    : m_opcode(opcode)
+inline ValueKey::ValueKey(Kind kind, Type type, Value* left, Value* right)
+    : m_kind(kind)
     , m_type(type)
 {
     u.indices[0] = left->index();
     u.indices[1] = right->index();
 }
 
-inline ValueKey::ValueKey(Opcode opcode, Type type, Value* a, Value* b, Value* c)
-    : m_opcode(opcode)
+inline ValueKey::ValueKey(Kind kind, Type type, Value* a, Value* b, Value* c)
+    : m_kind(kind)
     , m_type(type)
 {
     u.indices[0] = a->index();
index 01d541c..6aeef47 100644 (file)
@@ -46,18 +46,18 @@ Value* VariableValue::cloneImpl() const
     return new VariableValue(*this);
 }
 
-VariableValue::VariableValue(Opcode opcode, Origin origin, Variable* variable, Value* value)
-    : Value(CheckedOpcode, opcode, Void, origin, value)
+VariableValue::VariableValue(Kind kind, Origin origin, Variable* variable, Value* value)
+    : Value(CheckedOpcode, kind, Void, origin, value)
     , m_variable(variable)
 {
-    ASSERT(opcode == Set);
+    ASSERT(kind == Set);
 }
 
-VariableValue::VariableValue(Opcode opcode, Origin origin, Variable* variable)
-    : Value(CheckedOpcode, opcode, variable->type(), origin)
+VariableValue::VariableValue(Kind kind, Origin origin, Variable* variable)
+    : Value(CheckedOpcode, kind, variable->type(), origin)
     , m_variable(variable)
 {
-    ASSERT(opcode == Get);
+    ASSERT(kind == Get);
 }
 
 } } // namespace JSC::B3
index 4366e8a..067ba42 100644 (file)
@@ -35,7 +35,7 @@ class Variable;
 
 class JS_EXPORT_PRIVATE VariableValue : public Value {
 public:
-    static bool accepts(Opcode opcode) { return opcode == Get || opcode == Set; }
+    static bool accepts(Kind kind) { return kind == Get || kind == Set; }
 
     ~VariableValue();
 
@@ -50,10 +50,10 @@ private:
     friend class Procedure;
 
     // Use this for Set.
-    VariableValue(Opcode, Origin, Variable*, Value*);
+    VariableValue(Kind, Origin, Variable*, Value*);
 
     // Use this for Get.
-    VariableValue(Opcode, Origin, Variable*);
+    VariableValue(Kind, Origin, Variable*);
 
     Variable* m_variable;
 };
index f68274c..65d6f8c 100644 (file)
@@ -9976,7 +9976,7 @@ void testChillDiv(int num, int den, int res)
         root->appendNewControlValue(
             proc, Return, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
+                proc, chill(Div), Origin(),
                 root->appendNew<Value>(
                     proc, Trunc, Origin(),
                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
@@ -9995,7 +9995,7 @@ void testChillDiv(int num, int den, int res)
         root->appendNewControlValue(
             proc, Return, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
+                proc, chill(Div), Origin(),
                 root->appendNew<Const32Value>(proc, Origin(), num),
                 root->appendNew<Const32Value>(proc, Origin(), den)));
         
@@ -10013,7 +10013,7 @@ void testChillDivTwice(int num1, int den1, int num2, int den2, int res)
         root->appendNew<Value>(
             proc, Add, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
+                proc, chill(Div), Origin(),
                 root->appendNew<Value>(
                     proc, Trunc, Origin(),
                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
@@ -10021,7 +10021,7 @@ void testChillDivTwice(int num1, int den1, int num2, int den2, int res)
                     proc, Trunc, Origin(),
                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1))),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
+                proc, chill(Div), Origin(),
                 root->appendNew<Value>(
                     proc, Trunc, Origin(),
                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)),
@@ -10045,7 +10045,7 @@ void testChillDiv64(int64_t num, int64_t den, int64_t res)
         root->appendNewControlValue(
             proc, Return, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
+                proc, chill(Div), Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
         
@@ -10060,7 +10060,7 @@ void testChillDiv64(int64_t num, int64_t den, int64_t res)
         root->appendNewControlValue(
             proc, Return, Origin(),
             root->appendNew<Value>(
-                proc, ChillDiv, Origin(),
+                proc, chill(Div), Origin(),
                 root->appendNew<Const64Value>(proc, Origin(), num),
                 root->appendNew<Const64Value>(proc, Origin(), den)));
         
@@ -10179,7 +10179,7 @@ void testChillModArg(int64_t value)
     BasicBlock* root = proc.addBlock();
 
     Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
+    Value* result = root->appendNew<Value>(proc, chill(Mod), Origin(), argument, argument);
     root->appendNewControlValue(proc, Return, Origin(), result);
 
     CHECK(!compileAndRun<int64_t>(proc, value));
@@ -10192,7 +10192,7 @@ void testChillModArgs(int64_t numerator, int64_t denominator)
 
     Value* argument1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     Value* argument2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    Value* result = root->appendNew<Value>(proc, chill(Mod), Origin(), argument1, argument2);
     root->appendNewControlValue(proc, Return, Origin(), result);
 
     CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
@@ -10205,7 +10205,7 @@ void testChillModImms(int64_t numerator, int64_t denominator)
 
     Value* argument1 = root->appendNew<Const64Value>(proc, Origin(), numerator);
     Value* argument2 = root->appendNew<Const64Value>(proc, Origin(), denominator);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    Value* result = root->appendNew<Value>(proc, chill(Mod), Origin(), argument1, argument2);
     root->appendNewControlValue(proc, Return, Origin(), result);
 
     CHECK(compileAndRun<int64_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
@@ -10218,7 +10218,7 @@ void testChillModArg32(int32_t value)
 
     Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument, argument);
+    Value* result = root->appendNew<Value>(proc, chill(Mod), Origin(), argument, argument);
     root->appendNewControlValue(proc, Return, Origin(), result);
 
     CHECK(!compileAndRun<int32_t>(proc, value));
@@ -10233,7 +10233,7 @@ void testChillModArgs32(int32_t numerator, int32_t denominator)
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     Value* argument2 = root->appendNew<Value>(proc, Trunc, Origin(),
         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    Value* result = root->appendNew<Value>(proc, chill(Mod), Origin(), argument1, argument2);
     root->appendNewControlValue(proc, Return, Origin(), result);
 
     CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
@@ -10246,7 +10246,7 @@ void testChillModImms32(int32_t numerator, int32_t denominator)
 
     Value* argument1 = root->appendNew<Const32Value>(proc, Origin(), numerator);
     Value* argument2 = root->appendNew<Const32Value>(proc, Origin(), denominator);
-    Value* result = root->appendNew<Value>(proc, ChillMod, Origin(), argument1, argument2);
+    Value* result = root->appendNew<Value>(proc, chill(Mod), Origin(), argument1, argument2);
     root->appendNewControlValue(proc, Return, Origin(), result);
 
     CHECK(compileAndRun<int32_t>(proc, numerator, denominator) == chillMod(numerator, denominator));
@@ -10313,7 +10313,7 @@ void testSwitchChillDiv(unsigned degree, unsigned gap = 1)
         newBlock->appendNewControlValue(
             proc, Return, Origin(),
             newBlock->appendNew<Value>(
-                proc, ChillDiv, Origin(), (i & 1) ? right : left, (i & 1) ? left : right));
+                proc, chill(Div), Origin(), (i & 1) ? right : left, (i & 1) ? left : right));
         
         switchValue->appendCase(SwitchCase(gap * i, FrequentedBlock(newBlock)));
     }
@@ -12674,7 +12674,7 @@ void testEntrySwitchWithCommonPaths()
     end->appendNew<Value>(
         proc, Return, Origin(),
         end->appendNew<Value>(
-            proc, ChillMod, Origin(),
+            proc, chill(Mod), Origin(),
             phi, end->appendNew<Value>(
                 proc, Trunc, Origin(),
                 end->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))));
@@ -12791,7 +12791,7 @@ void testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint()
     end->appendNew<Value>(
         proc, Return, Origin(),
         end->appendNew<Value>(
-            proc, ChillMod, Origin(),
+            proc, chill(Mod), Origin(),
             phi, end->appendNew<Value>(
                 proc, Trunc, Origin(),
                 end->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2))));
index db5858e..4a833ff 100644 (file)
@@ -152,7 +152,7 @@ LValue Output::div(LValue left, LValue right)
 
 LValue Output::chillDiv(LValue left, LValue right)
 {
-    return m_block->appendNew<B3::Value>(m_proc, B3::ChillDiv, origin(), left, right);
+    return m_block->appendNew<B3::Value>(m_proc, chill(B3::Div), origin(), left, right);
 }
 
 LValue Output::mod(LValue left, LValue right)
@@ -162,7 +162,7 @@ LValue Output::mod(LValue left, LValue right)
 
 LValue Output::chillMod(LValue left, LValue right)
 {
-    return m_block->appendNew<B3::Value>(m_proc, B3::ChillMod, origin(), left, right);
+    return m_block->appendNew<B3::Value>(m_proc, chill(B3::Mod), origin(), left, right);
 }
 
 LValue Output::neg(LValue value)
index 346ae58..befb9ef 100644 (file)
@@ -1,3 +1,15 @@
+2016-09-28  Filip Pizlo  <fpizlo@apple.com>
+
+        B3 opcodes should leave room for flags
+        https://bugs.webkit.org/show_bug.cgi?id=162692
+
+        Reviewed by Keith Miller.
+        
+        Updated the documentation to talk about Kind and the isChill bit, and to remove
+        ChillDiv/ChillMod.
+
+        * docs/b3/intermediate-representation.html:
+
 2016-09-27  Joseph Pecoraro  <pecoraro@apple.com>
 
         Update style guide for #pragma once
index b4586e9..b1d3b2d 100644 (file)
     <h2>Values</h2>
 
     <p>Variables, and the instructions that define them, are represented using the Value object.
-      The Value object has a return type, an opcode, and zero or more children.  Children are
+      The Value object has a return type, a kind, and zero or more children.  Children are
       references to other Values.  Those values are used as input to the instruction that
       computes this value.</p>
+    
+    <p>The value kind is a combination of an opcode and optional flags. The flags allow a single
+      opcode to have many variants. For example, Div and Mod may have the Chill flag set to indicate
+      that they should not trap on corner cases.</p>
+    
     <p>Values also have a unique 32-bit index that is used as the name.</p>
     
     <p>Example:</p>
         according to the IEEE 854 spec.</dd>
 
       <dt>T Div(T, T)</dt>
-      <dd>Works with any type except Void.  For integer types, this represents signed division
-        with round-to-zero.  Its behavior is undefined for x/0 or -2<sup>31</sup>/-1.  For floating
-        point types, this represents division according to the IEEE 854 spec.</dd>
+      <dd>
+        <p>Works with any type except Void.  For integer types, this represents signed
+          division with round-to-zero.  By default, its behavior is undefined for x/0 or
+          -2<sup>31</sup>/-1.  For floating point types, this represents division according
+          to the IEEE 854 spec.</p>
+        <p>Integer Div may have the Chill flag set. You can create a Chill Div by saying
+          <code>chill(Div)</code> instead of <code>Div</code>; the former creates a Kind
+          that has Div as the opcode and has the Chill bit set. An operation is said to be
+          chill if it returns a sensible value whenever its non-chill form would have had
+          undefined behavior. Chill Div turns x/0 into 0 and -2<sup>31</sup>/-1 into
+          -2<sup>31</sup>. We recognize this in IR because it's exactly the semantics of
+          division on ARM64, and it's also exactly the semantics that JavaScript wants for
+          "(x/y)|0".</p>
+      </dd>
 
       <dt>T Mod(T, T)</dt>
-      <dd>Works with any type except Void.  For integer types, this represents signed modulo.
-        Its behavior is undefined for x%0 or -2<sup>31</sup>%-1.  For floating point types, this
-        represents modulo according to "fmod()".</dd>
+      <dd>
+        <p>Works with any type except Void.  For integer types, this represents signed
+          modulo. By default, its behavior is undefined for x%0 or -2<sup>31</sup>%-1.  For
+          floating point types, this represents modulo according to "fmod()".</p>
+        <p>Integer Mod may have the Chill flag set. You can create a Chill Mod by saying
+          <code>chill(Mod)</code>. Chill Mod turns x%0 into 0 and -2<sup>31</sup>%-1 into
+          0.</p>
+      </dd>
 
       <dt>T Neg(T)</dt>
       <dd>Works with any type except Void.  For integer types, this represents twos-complement
         negation.  For floating point types, this represents negation according to the IEEE
         spec.</dd>
 
-      <dt>T ChillDiv(T, T)</dt>
-      <dd>Chill division.  Valid for Int32 and Int64.  An operation is said to be chill if it
-        returns a sensible value whenever its non-chill form would have had undefined behavior.
-        ChillDiv turns x/0 into 0 and -2<sup>31</sup>/-1 into -2<sup>31</sup>.  This is a separate opcode
-        because it's exactly the semantics of division on ARM64, and it's also exactly the
-        semantics that JavaScript wants for "(x/y)|0".</dd>
-
-      <dt>T ChillMod(T, T)</dt>
-      <dd>Chill modulo.  Valid for Int32 and Int64.  ChllMod turns x%0 into 0 and
-        -2<sup>31</sup>%-1 into 0.</dd>
-
       <dt>T BitAnd(T, T)</dt>
       <dd>Bitwise and.  Valid for Int32 and Int64.</dd>