Title: [203996] trunk/Source/_javascript_Core
Revision
203996
Author
[email protected]
Date
2016-08-01 16:22:15 -0700 (Mon, 01 Aug 2016)

Log Message

[B3] Fusing immediates into test instructions should work again
https://bugs.webkit.org/show_bug.cgi?id=160073

Reviewed by Sam Weinig.

When we introduced BitImm, we forgot to change the Branch(BitAnd(value, constant))
fusion.  This emits test instructions, so it should use BitImm for the constant.  But it
was still using Imm!  This meant that isValidForm() always returned false.
        
This fixes the code path to use BitImm, and turns off our use of BitImm64 on x86 since
it provides no benefit on x86 and has some risk (the code appears to play fast and loose
with the scratch register).
        
This is not an obvious progression on anything, so I added comprehensive tests to
testb3, which check that we selected the optimal instruction in a variety of situations.
We should add more tests like this!

Rolling this back in after fixing ARM64. The bug was that branchTest32|64 on ARM64 doesn't
actually support BitImm or BitImm64, at least not yet. Disabling that in AirOpcodes makes
this patch not a regression on ARM64. That change was reviewed by Benjamin Poulain.

* b3/B3BasicBlock.h:
(JSC::B3::BasicBlock::successorBlock):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::createGenericCompare):
* b3/B3LowerToAir.h:
* b3/air/AirArg.cpp:
(JSC::B3::Air::Arg::isRepresentableAs):
(JSC::B3::Air::Arg::usesTmp):
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::isRepresentableAs):
(JSC::B3::Air::Arg::castToType):
(JSC::B3::Air::Arg::asNumber):
* b3/air/AirCode.h:
(JSC::B3::Air::Code::size):
(JSC::B3::Air::Code::at):
* b3/air/AirOpcode.opcodes:
* b3/air/AirValidate.h:
* b3/air/opcode_generator.rb:
* b3/testb3.cpp:
(JSC::B3::compile):
(JSC::B3::compileAndRun):
(JSC::B3::lowerToAirForTesting):
(JSC::B3::testSomeEarlyRegister):
(JSC::B3::testBranchBitAndImmFusion):
(JSC::B3::zero):
(JSC::B3::run):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (203995 => 203996)


--- trunk/Source/_javascript_Core/ChangeLog	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-08-01 23:22:15 UTC (rev 203996)
@@ -1,3 +1,53 @@
+2016-07-22  Filip Pizlo  <[email protected]>
+
+        [B3] Fusing immediates into test instructions should work again
+        https://bugs.webkit.org/show_bug.cgi?id=160073
+
+        Reviewed by Sam Weinig.
+
+        When we introduced BitImm, we forgot to change the Branch(BitAnd(value, constant))
+        fusion.  This emits test instructions, so it should use BitImm for the constant.  But it
+        was still using Imm!  This meant that isValidForm() always returned false.
+        
+        This fixes the code path to use BitImm, and turns off our use of BitImm64 on x86 since
+        it provides no benefit on x86 and has some risk (the code appears to play fast and loose
+        with the scratch register).
+        
+        This is not an obvious progression on anything, so I added comprehensive tests to
+        testb3, which check that we selected the optimal instruction in a variety of situations.
+        We should add more tests like this!
+
+        Rolling this back in after fixing ARM64. The bug was that branchTest32|64 on ARM64 doesn't
+        actually support BitImm or BitImm64, at least not yet. Disabling that in AirOpcodes makes
+        this patch not a regression on ARM64. That change was reviewed by Benjamin Poulain.
+
+        * b3/B3BasicBlock.h:
+        (JSC::B3::BasicBlock::successorBlock):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::createGenericCompare):
+        * b3/B3LowerToAir.h:
+        * b3/air/AirArg.cpp:
+        (JSC::B3::Air::Arg::isRepresentableAs):
+        (JSC::B3::Air::Arg::usesTmp):
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::isRepresentableAs):
+        (JSC::B3::Air::Arg::castToType):
+        (JSC::B3::Air::Arg::asNumber):
+        * b3/air/AirCode.h:
+        (JSC::B3::Air::Code::size):
+        (JSC::B3::Air::Code::at):
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirValidate.h:
+        * b3/air/opcode_generator.rb:
+        * b3/testb3.cpp:
+        (JSC::B3::compile):
+        (JSC::B3::compileAndRun):
+        (JSC::B3::lowerToAirForTesting):
+        (JSC::B3::testSomeEarlyRegister):
+        (JSC::B3::testBranchBitAndImmFusion):
+        (JSC::B3::zero):
+        (JSC::B3::run):
+
 2016-08-01  Filip Pizlo  <[email protected]>
 
         Rationalize varargs stack overflow checks

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2016-08-01 23:22:15 UTC (rev 203996)
@@ -1330,22 +1330,43 @@
                 Value* left = value->child(0);
                 Value* right = value->child(1);
 
-                // FIXME: We don't actually have to worry about leftImm.
-                // https://bugs.webkit.org/show_bug.cgi?id=150954
+                bool hasRightConst;
+                int64_t rightConst;
+                Arg rightImm;
+                Arg rightImm64;
 
-                Arg leftImm = imm(left);
-                Arg rightImm = imm(right);
+                hasRightConst = right->hasInt();
+                if (hasRightConst) {
+                    rightConst = right->asInt();
+                    rightImm = bitImm(right);
+                    rightImm64 = bitImm64(right);
+                }
                 
-                auto tryTestLoadImm = [&] (Arg::Width width, B3::Opcode loadOpcode) -> Inst {
-                    if (rightImm && rightImm.isRepresentableAs(width, Arg::Unsigned)) {
+                auto tryTestLoadImm = [&] (Arg::Width width, Arg::Signedness signedness, B3::Opcode loadOpcode) -> Inst {
+                    if (!hasRightConst)
+                        return Inst();
+                    // Signed loads will create high bits, so if the immediate has high bits
+                    // then we cannot proceed. Consider BitAnd(Load8S(ptr), 0x101). This cannot
+                    // be turned into testb (ptr), $1, since if the high bit within that byte
+                    // was set then it would be extended to include 0x100. The handling below
+                    // won't anticipate this, so we need to catch it here.
+                    if (signedness == Arg::Signed
+                        && !Arg::isRepresentableAs(width, Arg::Unsigned, rightConst))
+                        return Inst();
+                    
+                    // FIXME: If this is unsigned then we can chop things off of the immediate.
+                    // This might make the immediate more legal. Perhaps that's a job for
+                    // strength reduction?
+                    
+                    if (rightImm) {
                         if (Inst result = tryTest(width, loadPromise(left, loadOpcode), rightImm)) {
                             commitInternal(left);
                             return result;
                         }
                     }
-                    if (leftImm && leftImm.isRepresentableAs(width, Arg::Unsigned)) {
-                        if (Inst result = tryTest(width, leftImm, loadPromise(right, loadOpcode))) {
-                            commitInternal(right);
+                    if (rightImm64) {
+                        if (Inst result = tryTest(width, loadPromise(left, loadOpcode), rightImm64)) {
+                            commitInternal(left);
                             return result;
                         }
                     }
@@ -1355,24 +1376,28 @@
                 if (canCommitInternal) {
                     // First handle test's that involve fewer bits than B3's type system supports.
 
-                    if (Inst result = tryTestLoadImm(Arg::Width8, Load8Z))
+                    if (Inst result = tryTestLoadImm(Arg::Width8, Arg::Unsigned, Load8Z))
                         return result;
                     
-                    if (Inst result = tryTestLoadImm(Arg::Width8, Load8S))
+                    if (Inst result = tryTestLoadImm(Arg::Width8, Arg::Signed, Load8S))
                         return result;
                     
-                    if (Inst result = tryTestLoadImm(Arg::Width16, Load16Z))
+                    if (Inst result = tryTestLoadImm(Arg::Width16, Arg::Unsigned, Load16Z))
                         return result;
                     
-                    if (Inst result = tryTestLoadImm(Arg::Width16, Load16S))
+                    if (Inst result = tryTestLoadImm(Arg::Width16, Arg::Signed, Load16S))
                         return result;
 
-                    // Now handle test's that involve a load and an immediate. Note that immediates
-                    // are 32-bit, and we want zero-extension. Hence, the immediate form is compiled
-                    // as a 32-bit test. Note that this spits on the grave of inferior endians, such
-                    // as the big one.
+                    // This allows us to use a 32-bit test for 64-bit BitAnd if the immediate is
+                    // representable as an unsigned 32-bit value. The logic involved is the same
+                    // as if we were pondering using a 32-bit test for
+                    // BitAnd(SExt(Load(ptr)), const), in the sense that in both cases we have
+                    // to worry about high bits. So, we use the "Signed" version of this helper.
+                    if (Inst result = tryTestLoadImm(Arg::Width32, Arg::Signed, Load))
+                        return result;
                     
-                    if (Inst result = tryTestLoadImm(Arg::Width32, Load))
+                    // This is needed to handle 32-bit test for arbitrary 32-bit immediates.
+                    if (Inst result = tryTestLoadImm(width, Arg::Unsigned, Load))
                         return result;
                     
                     // Now handle test's that involve a load.
@@ -1391,30 +1416,23 @@
 
                 // Now handle test's that involve an immediate and a tmp.
 
-                if (leftImm) {
-                    if ((width == Arg::Width32 && leftImm.value() == 0xffffffff)
-                        || (width == Arg::Width64 && leftImm.value() == -1)) {
-                        ArgPromise argPromise = tmpPromise(right);
-                        if (Inst result = tryTest(width, argPromise, argPromise))
-                            return result;
-                    }
-                    if (leftImm.isRepresentableAs<uint32_t>()) {
-                        if (Inst result = tryTest(Arg::Width32, leftImm, tmpPromise(right)))
-                            return result;
-                    }
-                }
-
-                if (rightImm) {
-                    if ((width == Arg::Width32 && rightImm.value() == 0xffffffff)
-                        || (width == Arg::Width64 && rightImm.value() == -1)) {
+                if (hasRightConst) {
+                    if ((width == Arg::Width32 && rightConst == 0xffffffff)
+                        || (width == Arg::Width64 && rightConst == -1)) {
                         ArgPromise argPromise = tmpPromise(left);
                         if (Inst result = tryTest(width, argPromise, argPromise))
                             return result;
                     }
-                    if (rightImm.isRepresentableAs<uint32_t>()) {
+                    if (isRepresentableAs<uint32_t>(rightConst)) {
                         if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm))
                             return result;
+                        if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm64))
+                            return result;
                     }
+                    if (Inst result = tryTest(width, tmpPromise(left), rightImm))
+                        return result;
+                    if (Inst result = tryTest(width, tmpPromise(left), rightImm64))
+                        return result;
                 }
 
                 // Finally, just do tmp's.
@@ -1432,37 +1450,37 @@
             }
         }
 
-        if (Arg::isValidImmForm(-1)) {
+        if (Arg::isValidBitImmForm(-1)) {
             if (canCommitInternal && value->as<MemoryValue>()) {
                 // Handle things like Branch(Load8Z(value))
 
-                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8Z), Arg::imm(-1))) {
+                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8Z), Arg::bitImm(-1))) {
                     commitInternal(value);
                     return result;
                 }
 
-                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8S), Arg::imm(-1))) {
+                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8S), Arg::bitImm(-1))) {
                     commitInternal(value);
                     return result;
                 }
 
-                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16Z), Arg::imm(-1))) {
+                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16Z), Arg::bitImm(-1))) {
                     commitInternal(value);
                     return result;
                 }
 
-                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16S), Arg::imm(-1))) {
+                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16S), Arg::bitImm(-1))) {
                     commitInternal(value);
                     return result;
                 }
 
-                if (Inst result = tryTest(width, loadPromise(value), Arg::imm(-1))) {
+                if (Inst result = tryTest(width, loadPromise(value), Arg::bitImm(-1))) {
                     commitInternal(value);
                     return result;
                 }
             }
 
-            if (Inst result = test(width, resCond, tmpPromise(value), Arg::imm(-1)))
+            if (Inst result = test(width, resCond, tmpPromise(value), Arg::bitImm(-1)))
                 return result;
         }
         

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.h (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.h	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.h	2016-08-01 23:22:15 UTC (rev 203996)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-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
@@ -35,7 +35,7 @@
 
 // This lowers the current B3 procedure to an Air code.
 
-void lowerToAir(Procedure&);
+JS_EXPORT_PRIVATE void lowerToAir(Procedure&);
 
 } } // namespace JSC::B3
 

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.cpp (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/air/AirArg.cpp	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.cpp	2016-08-01 23:22:15 UTC (rev 203996)
@@ -57,31 +57,7 @@
 
 bool Arg::isRepresentableAs(Width width, Signedness signedness) const
 {
-    switch (signedness) {
-    case Signed:
-        switch (width) {
-        case Width8:
-            return isRepresentableAs<int8_t>();
-        case Width16:
-            return isRepresentableAs<int16_t>();
-        case Width32:
-            return isRepresentableAs<int32_t>();
-        case Width64:
-            return isRepresentableAs<int64_t>();
-        }
-    case Unsigned:
-        switch (width) {
-        case Width8:
-            return isRepresentableAs<uint8_t>();
-        case Width16:
-            return isRepresentableAs<uint16_t>();
-        case Width32:
-            return isRepresentableAs<uint32_t>();
-        case Width64:
-            return isRepresentableAs<uint64_t>();
-        }
-    }
-    ASSERT_NOT_REACHED();
+    return isRepresentableAs(width, signedness, value());
 }
 
 bool Arg::usesTmp(Air::Tmp tmp) const

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/air/AirArg.h	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h	2016-08-01 23:22:15 UTC (rev 203996)
@@ -793,8 +793,66 @@
     {
         return B3::isRepresentableAs<T>(value());
     }
+    
+    static bool isRepresentableAs(Width width, Signedness signedness, int64_t value)
+    {
+        switch (signedness) {
+        case Signed:
+            switch (width) {
+            case Width8:
+                return B3::isRepresentableAs<int8_t>(value);
+            case Width16:
+                return B3::isRepresentableAs<int16_t>(value);
+            case Width32:
+                return B3::isRepresentableAs<int32_t>(value);
+            case Width64:
+                return B3::isRepresentableAs<int64_t>(value);
+            }
+        case Unsigned:
+            switch (width) {
+            case Width8:
+                return B3::isRepresentableAs<uint8_t>(value);
+            case Width16:
+                return B3::isRepresentableAs<uint16_t>(value);
+            case Width32:
+                return B3::isRepresentableAs<uint32_t>(value);
+            case Width64:
+                return B3::isRepresentableAs<uint64_t>(value);
+            }
+        }
+        ASSERT_NOT_REACHED();
+    }
 
     bool isRepresentableAs(Width, Signedness) const;
+    
+    static int64_t castToType(Width width, Signedness signedness, int64_t value)
+    {
+        switch (signedness) {
+        case Signed:
+            switch (width) {
+            case Width8:
+                return static_cast<int8_t>(value);
+            case Width16:
+                return static_cast<int16_t>(value);
+            case Width32:
+                return static_cast<int32_t>(value);
+            case Width64:
+                return static_cast<int64_t>(value);
+            }
+        case Unsigned:
+            switch (width) {
+            case Width8:
+                return static_cast<uint8_t>(value);
+            case Width16:
+                return static_cast<uint16_t>(value);
+            case Width32:
+                return static_cast<uint32_t>(value);
+            case Width64:
+                return static_cast<uint64_t>(value);
+            }
+        }
+        ASSERT_NOT_REACHED();
+    }
 
     template<typename T>
     T asNumber() const
@@ -1300,11 +1358,11 @@
 
 namespace WTF {
 
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Kind);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Role);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Type);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Width);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Signedness);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Air::Arg::Kind);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Air::Arg::Role);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Air::Arg::Type);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Air::Arg::Width);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Air::Arg::Signedness);
 
 template<typename T> struct DefaultHash;
 template<> struct DefaultHash<JSC::B3::Air::Arg> {

Modified: trunk/Source/_javascript_Core/b3/air/AirCode.h (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/air/AirCode.h	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/air/AirCode.h	2016-08-01 23:22:15 UTC (rev 203996)
@@ -152,7 +152,7 @@
     // Recomputes predecessors and deletes unreachable blocks.
     void resetReachability();
 
-    void dump(PrintStream&) const;
+    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
 
     unsigned size() const { return m_blocks.size(); }
     BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2016-08-01 23:22:15 UTC (rev 203996)
@@ -675,23 +675,23 @@
     x86: RelCond, Index, Tmp
 
 BranchTest8 U:G:32, U:G:8, U:G:8 /branch
-    x86: ResCond, Addr, Imm
-    x86: ResCond, Index, Imm
+    x86: ResCond, Addr, BitImm
+    x86: ResCond, Index, BitImm
 
 BranchTest32 U:G:32, U:G:32, U:G:32 /branch
     ResCond, Tmp, Tmp
-    ResCond, Tmp, BitImm
-    x86: ResCond, Addr, Imm
-    x86: ResCond, Index, Imm
+    x86: ResCond, Tmp, BitImm
+    x86: ResCond, Addr, BitImm
+    x86: ResCond, Index, BitImm
 
 # Warning: forms that take an immediate will sign-extend their immediate. You probably want
 # BranchTest32 in most cases where you use an immediate.
 64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
     ResCond, Tmp, Tmp
-    ResCond, Tmp, BitImm64
-    x86: ResCond, Addr, Imm
+    x86: ResCond, Tmp, BitImm
+    x86: ResCond, Addr, BitImm
     x86: ResCond, Addr, Tmp
-    x86: ResCond, Index, Imm
+    x86: ResCond, Index, BitImm
 
 BranchDouble U:G:32, U:F:64, U:F:64 /branch
     DoubleCond, Tmp, Tmp

Modified: trunk/Source/_javascript_Core/b3/air/AirValidate.h (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/air/AirValidate.h	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/air/AirValidate.h	2016-08-01 23:22:15 UTC (rev 203996)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-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
@@ -32,7 +32,7 @@
 
 class Code;
 
-void validate(Code&, const char* dumpBefore = nullptr);
+JS_EXPORT_PRIVATE void validate(Code&, const char* dumpBefore = nullptr);
 
 } } } // namespace JSC::B3::Air
 

Modified: trunk/Source/_javascript_Core/b3/air/opcode_generator.rb (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2016-08-01 23:22:15 UTC (rev 203996)
@@ -490,7 +490,7 @@
     
     outp.puts "namespace WTF {"
     outp.puts "class PrintStream;"
-    outp.puts "void printInternal(PrintStream&, JSC::B3::Air::Opcode);"
+    outp.puts "JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Air::Opcode);"
     outp.puts "} // namespace WTF"
 }
 

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (203995 => 203996)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2016-08-01 23:22:15 UTC (rev 203996)
@@ -135,6 +135,22 @@
     return invoke<T>(*compile(procedure), arguments...);
 }
 
+void lowerToAirForTesting(Procedure& proc)
+{
+    proc.resetReachability();
+    
+    if (shouldBeVerbose())
+        dataLog("B3 before lowering:\n", proc);
+    
+    validate(proc);
+    lowerToAir(proc);
+    
+    if (shouldBeVerbose())
+        dataLog("Air after lowering:\n", proc.code());
+    
+    Air::validate(proc.code());
+}
+
 template<typename Type>
 struct Operand {
     const char* name;
@@ -12179,6 +12195,7 @@
     
     polyJump->setGenerator(
         [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
             Vector<Box<CCallHelpers::Label>> labels = params.successorLabels();
 
             MacroAssemblerCodePtr* jumpTable = bitwise_cast<MacroAssemblerCodePtr*>(
@@ -12811,6 +12828,48 @@
     run(false);
 }
 
+void testBranchBitAndImmFusion(
+    B3::Opcode valueModifier, Type valueType, int64_t constant,
+    Air::Opcode expectedOpcode, Air::Arg::Kind firstKind)
+{
+    // Currently this test should pass on all CPUs. But some CPUs may not support this fused
+    // instruction. It's OK to skip this test on those CPUs.
+    
+    Procedure proc;
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* _one_ = proc.addBlock();
+    BasicBlock* two = proc.addBlock();
+    
+    Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    
+    if (valueModifier != Identity) {
+        if (MemoryValue::accepts(valueModifier))
+            left = root->appendNew<MemoryValue>(proc, valueModifier, valueType, Origin(), left);
+        else
+            left = root->appendNew<Value>(proc, valueModifier, valueType, Origin(), left);
+    }
+    
+    root->appendNew<Value>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, BitAnd, Origin(), left,
+            root->appendIntConstant(proc, Origin(), valueType, constant)));
+    root->setSuccessors(FrequentedBlock(one), FrequentedBlock(two));
+    
+    one->appendNew<Value>(proc, Oops, Origin());
+    two->appendNew<Value>(proc, Oops, Origin());
+
+    lowerToAirForTesting(proc);
+
+    // The first basic block must end in a BranchTest64(resCond, tmp, bitImm).
+    Air::Inst terminal = proc.code()[0]->last();
+    CHECK_EQ(terminal.opcode, expectedOpcode);
+    CHECK_EQ(terminal.args[0].kind(), Air::Arg::ResCond);
+    CHECK_EQ(terminal.args[1].kind(), firstKind);
+    CHECK(terminal.args[2].kind() == Air::Arg::BitImm || terminal.args[2].kind() == Air::Arg::BitImm64);
+}
+
 // Make sure the compiler does not try to optimize anything out.
 NEVER_INLINE double zero()
 {
@@ -14224,6 +14283,17 @@
 
     RUN(testSomeEarlyRegister());
     
+    if (isX86()) {
+        RUN(testBranchBitAndImmFusion(Identity, Int64, 1, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Identity, Int64, 0xff, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Trunc, Int32, 1, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Trunc, Int32, 0xff, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Load8S, Int32, 1, Air::BranchTest8, Air::Arg::Addr));
+        RUN(testBranchBitAndImmFusion(Load8Z, Int32, 1, Air::BranchTest8, Air::Arg::Addr));
+        RUN(testBranchBitAndImmFusion(Load, Int32, 1, Air::BranchTest32, Air::Arg::Addr));
+        RUN(testBranchBitAndImmFusion(Load, Int64, 1, Air::BranchTest32, Air::Arg::Addr));
+    }
+
     if (tasks.isEmpty())
         usage();
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to