Title: [279470] trunk/Source/_javascript_Core
Revision
279470
Author
commit-qu...@webkit.org
Date
2021-07-01 10:25:26 -0700 (Thu, 01 Jul 2021)

Log Message

Add a new pattern to instruction selector to use EXTR supported by ARM64
https://bugs.webkit.org/show_bug.cgi?id=227171

Patch by Yijia Huang <yijia_hu...@apple.com> on 2021-07-01
Reviewed by Robin Morisset.

This patch includes two modifications:
    1. Introduce a strength reduction rule to zero extend bitfield.
    2. Add Extract Register (EXTR) to Air opcode to serve instruction selector.

-------------------------------------------------------
### Part A zero extend bitfield ###
-------------------------------------------------------
A new strength reduction rule is added for the canonical form of the zero-extend
bitfield.

Turn this: ZShr(Shl(value, amount)), amount)
Into this: BitAnd(value, mask)

with constraints:
1. 0 <= amount < datasize
2. width = datasize - amount
3. mask is !(mask & (mask + 1)) where bitCount(mask) == width

-------------------
### Part B EXTR ###
-------------------

Given instruction:
extr Rd, Rn, Rm, lowWidth

Extract register (EXTR) extracts a register from a pair of registers, where
concat = Rn:Rm and Rd = concat<lowWidth + datasize - 1:lowWidth>.

The equivalent pattern of this instruction is:

d = ((n & mask) << highWidth) | (m >> lowWidth)
highWidth = datasize - lowWidth
mask = (1 << lowWidth) - 1

Given B3 IR:
Int @0 = ArgumentReg(%x0)
Int @1 = ArgumentReg(%x1)
Int @2 = mask
Int @3 = BitAnd(@0, @2)
Int @4 = highWidth
Int @5 = Shl(@3, @4)
Int @6 = lowWidth
Int @7 = ZShr(@1, @6)
Int @8 = BitOr(@7, @5)
Void@9 = Return(@10, Terminal)

Before Adding BIC:
// Old optimized AIR
InsertUnsignedBitfieldInZero %x0, highWidth, lowWidth, %x0, @5
Urshift                      %x1,  lowWidth,      %x1,      @7
Or                           %x0,       %x1,      %x0,      @8
Ret                          %x0,                           @9

After Adding BIC:
// New optimized AIR
ExtractRegister   %x0, %x1, lowWidth, %x0, @8
Ret               %x0,                     @9

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::extractRegister32):
(JSC::MacroAssemblerARM64::extractRegister64):
* assembler/testmasm.cpp:
(JSC::testExtractRegister32):
(JSC::testExtractRegister64):
* b3/B3LowerToAir.cpp:
* b3/B3ReduceStrength.cpp:
* b3/air/AirOpcode.opcodes:
* b3/testb3.h:
* b3/testb3_2.cpp:
(testBitfieldZeroExtend32):
(testBitfieldZeroExtend64):
(testExtractRegister32):
(testExtractRegister64):
(addBitTests):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (279469 => 279470)


--- trunk/Source/_javascript_Core/ChangeLog	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-07-01 17:25:26 UTC (rev 279470)
@@ -1,3 +1,85 @@
+2021-07-01  Yijia Huang  <yijia_hu...@apple.com>
+
+        Add a new pattern to instruction selector to use EXTR supported by ARM64
+        https://bugs.webkit.org/show_bug.cgi?id=227171
+
+        Reviewed by Robin Morisset.
+
+        This patch includes two modifications:
+            1. Introduce a strength reduction rule to zero extend bitfield.
+            2. Add Extract Register (EXTR) to Air opcode to serve instruction selector.
+
+        -------------------------------------------------------
+        ### Part A zero extend bitfield ###
+        -------------------------------------------------------
+        A new strength reduction rule is added for the canonical form of the zero-extend 
+        bitfield.
+
+        Turn this: ZShr(Shl(value, amount)), amount)
+        Into this: BitAnd(value, mask)
+
+        with constraints:
+        1. 0 <= amount < datasize
+        2. width = datasize - amount
+        3. mask is !(mask & (mask + 1)) where bitCount(mask) == width
+
+        -------------------
+        ### Part B EXTR ###
+        -------------------
+
+        Given instruction:
+        extr Rd, Rn, Rm, lowWidth
+
+        Extract register (EXTR) extracts a register from a pair of registers, where 
+        concat = Rn:Rm and Rd = concat<lowWidth + datasize - 1:lowWidth>.
+
+        The equivalent pattern of this instruction is:
+
+        d = ((n & mask) << highWidth) | (m >> lowWidth)
+        highWidth = datasize - lowWidth
+        mask = (1 << lowWidth) - 1
+
+        Given B3 IR:
+        Int @0 = ArgumentReg(%x0)
+        Int @1 = ArgumentReg(%x1)
+        Int @2 = mask
+        Int @3 = BitAnd(@0, @2)
+        Int @4 = highWidth
+        Int @5 = Shl(@3, @4)
+        Int @6 = lowWidth
+        Int @7 = ZShr(@1, @6)
+        Int @8 = BitOr(@7, @5)
+        Void@9 = Return(@10, Terminal)
+
+        Before Adding BIC:
+        // Old optimized AIR
+        InsertUnsignedBitfieldInZero %x0, highWidth, lowWidth, %x0, @5
+        Urshift                      %x1,  lowWidth,      %x1,      @7
+        Or                           %x0,       %x1,      %x0,      @8
+        Ret                          %x0,                           @9
+
+        After Adding BIC:
+        // New optimized AIR
+        ExtractRegister   %x0, %x1, lowWidth, %x0, @8
+        Ret               %x0,                     @9
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::extractRegister32):
+        (JSC::MacroAssemblerARM64::extractRegister64):
+        * assembler/testmasm.cpp:
+        (JSC::testExtractRegister32):
+        (JSC::testExtractRegister64):
+        * b3/B3LowerToAir.cpp:
+        * b3/B3ReduceStrength.cpp:
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.h:
+        * b3/testb3_2.cpp:
+        (testBitfieldZeroExtend32):
+        (testBitfieldZeroExtend64):
+        (testExtractRegister32):
+        (testExtractRegister64):
+        (addBitTests):
+
 2021-06-30  Saam Barati  <sbar...@apple.com>
 
         Turn off data ICs by default
@@ -347,8 +429,8 @@
         Reviewed by Filip Pizlo.
 
         This patch includes three modifications:
-            1. Add bit clear (BIC), or not (ORN), and extract and insert bitfield at lower end (BFXIL) 
-               to Air opcode to serve intruciton selector.
+            1. Add bit clear (BIC), or not (ORN), and extract and insert bitfield at the 
+               lower end (BFXIL) to Air opcode to serve instruction selector.
             2. Add bitfield clear (BFC) to MacroAssembler.
             4. Do refactoring - rename Air opcodes added in the previous patches.
 
@@ -370,7 +452,7 @@
         Pattern 2:
             d = n & (m ^ -1)
 
-        In order to get benefits for complement operation, current instruction selector uses 
+        In order to get benefits for complement operation, the current instruction selector uses 
         mvn instruction to lower the pattern value ^ -1. Then, a new strength reduction rule is 
         introduced:
             Turn this: -value - 1 
@@ -1202,7 +1284,7 @@
             A) Add UBFIZ to instruction selector.
             B) Fix UBFX, introduced in https://bugs.webkit.org/show_bug.cgi?id=226984, 
                to match all patterns. 
-            C) Fix error condition in one strength reduction introduced 
+            C) Fix error condition in one strength reduction rule introduced 
                in https://bugs.webkit.org/show_bug.cgi?id=227138.
 
         Part A

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (279469 => 279470)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-07-01 17:25:26 UTC (rev 279470)
@@ -539,6 +539,16 @@
         m_assembler.sbfx<64>(dest, src, lsb.m_value, width.m_value);
     }    
 
+    void extractRegister32(RegisterID n, RegisterID m, TrustedImm32 lsb, RegisterID d)
+    {
+        m_assembler.extr<32>(d, n, m, lsb.m_value);
+    }
+
+    void extractRegister64(RegisterID n, RegisterID m, TrustedImm32 lsb, RegisterID d)
+    {
+        m_assembler.extr<64>(d, n, m, lsb.m_value);
+    } 
+
     void clearBit64(RegisterID bitToClear, RegisterID dest, RegisterID scratchForMask = InvalidGPRReg)
     {
         if (scratchForMask == InvalidGPRReg)

Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (279469 => 279470)


--- trunk/Source/_javascript_Core/assembler/testmasm.cpp	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp	2021-07-01 17:25:26 UTC (rev 279470)
@@ -1570,6 +1570,76 @@
     }
 }
 
+void testExtractRegister32()
+{
+    Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 };
+    uint32_t datasize = CHAR_BIT * sizeof(uint32_t);
+
+    for (auto n : int32Operands()) {
+        for (auto m : int32Operands()) {
+            for (auto lsb : imms) {
+                if (0 <= lsb && lsb < datasize) {
+                    auto extractRegister32 = compile([=] (CCallHelpers& jit) {
+                        emitFunctionPrologue(jit);
+
+                        jit.extractRegister32(GPRInfo::argumentGPR0, 
+                            GPRInfo::argumentGPR1, 
+                            CCallHelpers::TrustedImm32(lsb), 
+                            GPRInfo::returnValueGPR);
+
+                        emitFunctionEpilogue(jit);
+                        jit.ret();
+                    });
+
+                    // ((n & mask) << highWidth) | (m >> lowWidth)
+                    // Where: highWidth = datasize - lowWidth
+                    //        mask = (1 << lowWidth) - 1
+                    uint32_t highWidth = datasize - lsb;
+                    uint32_t mask = (1U << lsb) - 1U;
+                    uint32_t left = highWidth == datasize ? 0U : (n & mask) << highWidth;
+                    uint32_t right = (static_cast<uint32_t>(m) >> lsb);
+                    uint32_t rhs = left | right;
+                    uint32_t lhs = invoke<uint32_t>(extractRegister32, n, m);
+                    CHECK_EQ(lhs, rhs);
+                }
+            }
+        }
+    }
+}
+
+void testExtractRegister64()
+{
+    Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 };
+    uint64_t datasize = CHAR_BIT * sizeof(uint64_t);
+
+    for (auto n : int64Operands()) {
+        for (auto m : int64Operands()) {
+            for (auto lsb : imms) {
+                if (0 <= lsb && lsb < datasize) {
+                    auto extractRegister64 = compile([=] (CCallHelpers& jit) {
+                        emitFunctionPrologue(jit);
+
+                        jit.extractRegister64(GPRInfo::argumentGPR0, 
+                            GPRInfo::argumentGPR1, 
+                            CCallHelpers::TrustedImm32(lsb), 
+                            GPRInfo::returnValueGPR);
+
+                        emitFunctionEpilogue(jit);
+                        jit.ret();
+                    });
+
+                    uint64_t highWidth = datasize - lsb;
+                    uint64_t mask = (1ULL << lsb) - 1ULL;
+                    uint64_t left = highWidth == datasize ? 0ULL : (n & mask) << highWidth;
+                    uint64_t right = (static_cast<uint64_t>(m) >> lsb);
+                    uint64_t rhs = left | right;
+                    uint64_t lhs = invoke<uint64_t>(extractRegister64, n, m);
+                    CHECK_EQ(lhs, rhs);
+                }
+            }
+        }
+    }
+}
 #endif
 
 #if CPU(X86) || CPU(X86_64) || CPU(ARM64)
@@ -3760,6 +3830,8 @@
     RUN(testInsertSignedBitfieldInZero64());
     RUN(testExtractSignedBitfield32());
     RUN(testExtractSignedBitfield64());
+    RUN(testExtractRegister32());
+    RUN(testExtractRegister64());
 #endif
 
 #if CPU(X86) || CPU(X86_64) || CPU(ARM64)

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (279469 => 279470)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2021-07-01 17:25:26 UTC (rev 279470)
@@ -2824,6 +2824,45 @@
             Value* left = m_value->child(0);
             Value* right = m_value->child(1);
 
+            // EXTR Pattern: d = ((n & mask) << highWidth) | (m >> lowWidth)
+            // Where: highWidth = datasize - lowWidth
+            //        mask = (1 << lowWidth) - 1
+            auto tryAppendEXTR = [&] (Value* left, Value* right) -> bool {
+                Air::Opcode opcode = opcodeForType(ExtractRegister32, ExtractRegister64, m_value->type());
+                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Imm, Arg::Tmp)) 
+                    return false;
+                if (left->opcode() != Shl || left->child(0)->opcode() != BitAnd || right->opcode() != ZShr)
+                    return false;
+
+                Value* nValue = left->child(0)->child(0);
+                Value* maskValue = left->child(0)->child(1);
+                Value* highWidthValue = left->child(1);
+                Value* mValue = right->child(0);
+                Value* lowWidthValue = right->child(1);
+                if (m_locked.contains(nValue) || m_locked.contains(mValue) || !maskValue->hasInt())
+                    return false;
+                if (!imm(highWidthValue) || highWidthValue->asInt() < 0)
+                    return false;
+                if (!imm(lowWidthValue) || lowWidthValue->asInt() < 0)
+                    return false;
+
+                uint64_t mask = maskValue->asInt();
+                if (!mask || mask & (mask + 1))
+                    return false;
+                uint64_t maskBitCount = WTF::bitCount(mask);
+                uint64_t highWidth = highWidthValue->asInt();
+                uint64_t lowWidth = lowWidthValue->asInt();
+                uint64_t datasize = opcode == ExtractRegister32 ? 32 : 64;
+                if (lowWidth + highWidth != datasize || maskBitCount != lowWidth)
+                    return false;
+
+                append(opcode, tmp(nValue), tmp(mValue), imm(lowWidthValue), tmp(m_value));
+                return true;
+            };
+
+            if (tryAppendEXTR(left, right) || tryAppendEXTR(right, left))
+                return;           
+
             // BFI Pattern: d = ((n & mask1) << lsb) | (d & mask2)
             // Where: mask1 = ((1 << width) - 1)
             //        mask2 = ~(mask1 << lsb)

Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (279469 => 279470)


--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2021-07-01 17:25:26 UTC (rev 279470)
@@ -1463,6 +1463,33 @@
                 break;
             }
 
+            // Turn this: ZShr(Shl(value, amount)), amount)
+            // Into this: BitAnd(value, mask)
+            // Conditions:
+            // 1. 0 <= amount < datasize
+            // 2. width = datasize - amount
+            // 3. mask is !(mask & (mask + 1)) where bitCount(mask) == width
+            if (m_value->child(0)->opcode() == Shl
+                && m_value->child(0)->child(1)->hasInt()
+                && m_value->child(0)->child(1)->asInt() >= 0
+                && m_value->child(1)->hasInt()
+                && m_value->child(1)->asInt() >= 0) {
+                uint64_t amount1 = m_value->child(0)->child(1)->asInt();
+                uint64_t amount2 = m_value->child(1)->asInt();
+                uint64_t datasize = m_value->child(0)->child(0)->type() == Int64 ? 64 : 32;
+                if (amount1 == amount2 && amount1 < datasize) {
+                    uint64_t width = datasize - amount1;
+                    uint64_t mask = (1ULL << width) - 1ULL;
+                    Value* maskValue;
+                    if (datasize == 32)
+                        maskValue = m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), mask);
+                    else
+                        maskValue = m_insertionSet.insert<Const64Value>(m_index, m_value->origin(), mask);
+                    replaceWithNew<Value>(BitAnd, m_value->origin(), m_value->child(0)->child(0), maskValue);
+                    break;
+                }
+            }
+
             // Turn this: ZShr(BitAnd(value, maskShift), shiftAmount)
             // Into this: BitAnd(ZShr(value, shiftAmount), mask)
             // Conditions:

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (279469 => 279470)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2021-07-01 17:25:26 UTC (rev 279470)
@@ -866,6 +866,12 @@
 arm64: ExtractSignedBitfield64 U:G:64, U:G:32, U:G:32, D:G:64
     Tmp, Imm, Imm, Tmp
 
+arm64: ExtractRegister32 U:G:32, U:G:32, U:G:32, ZD:G:32
+    Tmp, Tmp, Imm, Tmp
+
+arm64: ExtractRegister64 U:G:64, U:G:32, U:G:32, D:G:64
+    Tmp, Tmp, Imm, Tmp
+
 # The first operand is rax.
 # FIXME: This formulation means that the boolean result cannot be put in eax, even though all users
 # of this would be OK with that.

Modified: trunk/Source/_javascript_Core/b3/testb3.h (279469 => 279470)


--- trunk/Source/_javascript_Core/b3/testb3.h	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/b3/testb3.h	2021-07-01 17:25:26 UTC (rev 279470)
@@ -436,6 +436,10 @@
 void testBIC64();
 void testOrNot32();
 void testOrNot64();
+void testBitfieldZeroExtend32();
+void testBitfieldZeroExtend64();
+void testExtractRegister32();
+void testExtractRegister64();
 void testInsertSignedBitfieldInZero32();
 void testInsertSignedBitfieldInZero64();
 void testExtractSignedBitfield32();

Modified: trunk/Source/_javascript_Core/b3/testb3_2.cpp (279469 => 279470)


--- trunk/Source/_javascript_Core/b3/testb3_2.cpp	2021-07-01 17:14:18 UTC (rev 279469)
+++ trunk/Source/_javascript_Core/b3/testb3_2.cpp	2021-07-01 17:25:26 UTC (rev 279470)
@@ -3703,6 +3703,200 @@
     }
 }
 
+void testBitfieldZeroExtend32()
+{
+    if (JSC::Options::defaultB3OptLevel() < 2)
+        return;
+    Vector<uint32_t> amounts = { 0, 14, 31 };
+
+    // Turn this: ZShr(Shl(n, amount)), amount)
+    // Into this: BitAnd(n, mask)
+    // Conditions:
+    // 1. 0 <= amount < datasize
+    // 2. width = datasize - amount
+    // 3. mask is !(mask & (mask + 1)) where bitCount(mask) == width
+    auto test = [&] (uint32_t n, uint32_t amount) -> uint32_t {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* nValue = root->appendNew<Value>(
+            proc, Trunc, Origin(), 
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* shlValue = root->appendNew<Value>(proc, Shl, Origin(), nValue, amountValue);
+        Value* zshrValue = root->appendNew<Value>(proc, ZShr, Origin(), shlValue, amountValue);
+        root->appendNewControlValue(proc, Return, Origin(), zshrValue);
+
+        auto code = compileProc(proc);
+        if (isARM64() && amount > 0)
+            checkUsesInstruction(*code, "and");
+        return invoke<uint32_t>(*code, n, amount);
+    };
+
+    uint32_t datasize = CHAR_BIT * sizeof(uint32_t);
+    for (auto nOperand : int32Operands()) {
+        for (auto amount : amounts) {
+            uint32_t n = nOperand.value;
+            uint32_t width = datasize - amount;
+            uint32_t mask = width == datasize ? std::numeric_limits<uint32_t>::max() : (1U << width) - 1U;
+            uint32_t lhs = test(n, amount);
+            uint32_t rhs = (n & mask);
+            CHECK(lhs == rhs);
+        }
+    }
+}
+
+void testBitfieldZeroExtend64()
+{
+    if (JSC::Options::defaultB3OptLevel() < 2)
+        return;
+    Vector<uint64_t> amounts = { 0, 34, 63 };
+
+    auto test = [&] (uint64_t n, uint64_t amount) -> uint64_t {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* shlValue = root->appendNew<Value>(proc, Shl, Origin(), nValue, amountValue);
+        Value* zshrValue = root->appendNew<Value>(proc, ZShr, Origin(), shlValue, amountValue);
+        root->appendNewControlValue(proc, Return, Origin(), zshrValue);
+
+        auto code = compileProc(proc);
+        if (isARM64() && amount > 0)
+            checkUsesInstruction(*code, "and");
+        return invoke<uint64_t>(*code, n, amount);
+    };
+
+    uint64_t datasize = CHAR_BIT * sizeof(uint64_t);
+    for (auto nOperand : int64Operands()) {
+        for (auto amount : amounts) {
+            uint64_t n = nOperand.value;
+            uint64_t width = datasize - amount;
+            uint64_t mask = width == datasize ? std::numeric_limits<uint64_t>::max() : (1ULL << width) - 1ULL;
+            uint64_t lhs = test(n, amount);
+            uint64_t rhs = (n & mask);
+            CHECK(lhs == rhs);
+        }
+    }
+}
+
+void testExtractRegister32()
+{
+    if (JSC::Options::defaultB3OptLevel() < 2)
+        return;    
+    Vector<uint32_t> lowWidths = { 0, 17, 31 };
+
+    // Test Pattern: ((n & mask1) << highWidth) | ((m & mask2) >> lowWidth)
+    // Where: highWidth = datasize - lowWidth
+    //        mask1 = (1 << lowWidth) - 1
+    //        mask2 = ~mask1
+    auto test = [&] (uint32_t n, uint32_t m, uint32_t mask1, uint32_t mask2, uint32_t highWidth, uint32_t lowWidth) -> uint32_t {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* nValue = root->appendNew<Value>(
+            proc, Trunc, Origin(), 
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* mValue = root->appendNew<Value>(
+            proc, Trunc, Origin(), 
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* mask1Value = root->appendNew<Const32Value>(proc, Origin(), mask1);
+        Value* mask2Value = root->appendNew<Const32Value>(proc, Origin(), mask2);
+        Value* highWidthValue = root->appendNew<Const32Value>(proc, Origin(), highWidth);
+        Value* lowWidthValue = root->appendNew<Const32Value>(proc, Origin(), lowWidth);
+
+        Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), nValue, mask1Value);
+        Value* left = root->appendNew<Value>(proc, Shl, Origin(), leftAndValue, highWidthValue);
+
+        Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), mValue, mask2Value);
+        Value* right = root->appendNew<Value>(proc, ZShr, Origin(), rightAndValue, lowWidthValue);
+
+        root->appendNewControlValue(
+            proc, Return, Origin(), 
+            root->appendNew<Value>(proc, BitOr, Origin(), left, right));
+
+        auto code = compileProc(proc);
+        if (isARM64() && lowWidth > 0)
+            checkUsesInstruction(*code, "extr");
+        return invoke<uint32_t>(*code, n, m);
+    };
+
+    uint32_t datasize = CHAR_BIT * sizeof(uint32_t);
+    for (auto nOperand : int32Operands()) {
+        for (auto mOperand : int32Operands()) {
+            for (auto lowWidth : lowWidths) {
+                uint32_t n = nOperand.value;
+                uint32_t m = mOperand.value;
+                uint32_t highWidth = datasize - lowWidth;
+                uint32_t mask1 = (1U << lowWidth) - 1U;
+                uint32_t mask2 = ~mask1;
+                uint32_t left = highWidth == datasize ? 0U : ((n & mask1) << highWidth);
+                uint32_t right = ((m & mask2) >> lowWidth);
+                uint32_t rhs = left | right;
+                uint32_t lhs = test(n, m, mask1, mask2, highWidth, lowWidth);
+                CHECK(lhs == rhs);
+            }
+        }
+    }
+}
+
+void testExtractRegister64()
+{
+    if (JSC::Options::defaultB3OptLevel() < 2)
+        return;    
+    Vector<uint64_t> lowWidths = { 0, 34, 63 };
+
+    // Test Pattern: ((n & mask1) << highWidth) | ((m & mask2) >> lowWidth)
+    // Where: highWidth = datasize - lowWidth
+    //        mask1 = (1 << lowWidth) - 1
+    //        mask2 = ~mask1
+    auto test = [&] (uint64_t n, uint64_t m, uint64_t mask1, uint64_t mask2, uint64_t highWidth, uint64_t lowWidth) -> uint64_t {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+        Value* mask1Value = root->appendNew<Const64Value>(proc, Origin(), mask1);
+        Value* mask2Value = root->appendNew<Const64Value>(proc, Origin(), mask2);
+        Value* highWidthValue = root->appendNew<Const32Value>(proc, Origin(), highWidth);
+        Value* lowWidthValue = root->appendNew<Const32Value>(proc, Origin(), lowWidth);
+
+        Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), nValue, mask1Value);
+        Value* left = root->appendNew<Value>(proc, Shl, Origin(), leftAndValue, highWidthValue);
+
+        Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), mValue, mask2Value);
+        Value* right = root->appendNew<Value>(proc, ZShr, Origin(), rightAndValue, lowWidthValue);
+
+        root->appendNewControlValue(
+            proc, Return, Origin(), 
+            root->appendNew<Value>(proc, BitOr, Origin(), left, right));
+
+        auto code = compileProc(proc);
+        if (isARM64() && lowWidth > 0)
+            checkUsesInstruction(*code, "extr");
+        return invoke<uint64_t>(*code, n, m);
+    };
+
+    uint64_t datasize = CHAR_BIT * sizeof(uint64_t);
+    for (auto nOperand : int64Operands()) {
+        for (auto mOperand : int64Operands()) {
+            for (auto lowWidth : lowWidths) {
+                uint64_t n = nOperand.value;
+                uint64_t m = mOperand.value;
+                uint64_t highWidth = datasize - lowWidth;
+                uint64_t mask1 = (1ULL << lowWidth) - 1ULL;
+                uint64_t mask2 = ~mask1;
+                uint64_t left = highWidth == datasize ? 0ULL : ((n & mask1) << highWidth);
+                uint64_t right = ((m & mask2) >> lowWidth);
+                uint64_t rhs = left | right;
+                uint64_t lhs = test(n, m, mask1, mask2, highWidth, lowWidth);
+                CHECK(lhs == rhs);
+            }
+        }
+    }
+}
+
 void testBitAndZeroShiftRightArgImmMask32()
 {
     // Turn this: (tmp >> imm) & mask 
@@ -4603,6 +4797,10 @@
     RUN(testBIC64());
     RUN(testOrNot32());
     RUN(testOrNot64());
+    RUN(testBitfieldZeroExtend32());
+    RUN(testBitfieldZeroExtend64());
+    RUN(testExtractRegister32());
+    RUN(testExtractRegister64());
     RUN(testInsertSignedBitfieldInZero32());
     RUN(testInsertSignedBitfieldInZero64());
     RUN(testExtractSignedBitfield32());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to