⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 279362 in webkit


Ignore:
Timestamp:
Jun 28, 2021, 9:05:14 PM (5 years ago)
Author:
commit-queue@webkit.org
Message:

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

Patch by Yijia Huang <Yijia Huang> on 2021-06-28
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 (FBXIL) to Air opcode to serve intruciton selector.
  2. Add bitfield clear (BFC) to MacroAssembler.
  3. Do refactoring - rename Air opcodes added in the previous patches.

### Part A BIC ###


Given the operation:

bic Rd, Rn, Rm

The BIC (Bit Clear) instruction performs an AND operation on the bits in Rn with the
complements of the corresponding bits in the value of Rm. The instruction selector can
utilize this to lowering certain patterns in B3 IR before further Air optimization.
The equivalent patterns of this instruction are:

Pattern 1:

d = n & (-m - 1)

Pattern 2:

d = n & (m -1)

In order to get benefits for complement operation, current instruction selector uses
mvn instruction to lower the pattern value -1. Then, a new strength reduction rule is
introduced:

Turn this: -value - 1
Into this: value -1

So, d = n & (m -1) is selected as the canonical form.

Given B3 IR:
Int @0 = ArgumentReg(%x0)
Int @1 = ArgumentReg(%x1)
Int @2 = -1
Int @3 = BitXor(@1, @2)
Int @4 = BitAnd(@0, @3)
Void@5 = Return(@4, Terminal)

Before Adding BIC:
Old optimized AIR
Not %x1, %x1, @3
And %x0, %x1, %x0, @4
Ret %x0, @5

After Adding BIC:
New optimized AIR
Bic %x0, %x1, %x0, @4
Ret %x0, @5


### Part A ORN ###


Given the operation:

orn Rd, Rn, Rm

Bitwise OR NOT (shifted register) performs a bitwise (inclusive) OR of a register value
Rn and the complement of an optionally-shifted register value Rm, and writes the result
to the destination register Rd.

The equivalent patterns of this instruction are:

Pattern 1:

d = n | (-m - 1)

Pattern 2:

d = n | (m -1)

Then, d = n | (m -1) is selected as the canonical form.

Given B3 IR:
Int @0 = ArgumentReg(%x0)
Int @1 = ArgumentReg(%x1)
Int @2 = -1
Int @3 = BitXor(@1, @2)
Int @4 = BitOr(@0, @3)
Void@5 = Return(@4, Terminal)

Before Adding BIC:
Old optimized AIR
Not %x1, %x1, @3
Or %x0, %x1, %x0, @4
Ret %x0, @5

After Adding BIC:
New optimized AIR
Orn %x0, %x1, %x0, @4
Ret %x0, @5


### Part A FBXIL ###


Given the operation:

bfxil Rd, Rn, lsb, width

Bitfield extract and insert at low end(FBXIL) copies any number of low-order bits
from a source register into the same number of adjacent bits at the low end in
the destination register, leaving other bits unchanged.

The equivalent patterns of this instruction are:

Pattern 1:
mask1 = (1 << width) - 1
mask2 = ~mask1
((n >> lsb) & mask1) | (d & mask2)

Pattern 2:
mask1 = ((1 << width) - 1) << lsb
mask2 = ~(mask1 >> lsb)
((n & mask1) >> lsb) | (d & mask2)

Then, introduce a strength reduction rule for easier recognization.
Turn this: (v & maskShift) >> shiftAmount
Into this: (v >> shiftAmount) & mask

with constraints:

  1. maskShift = mask << lsb
  2. mask = (1 << width) - 1
  3. 0 <= shiftAmount < datasize
  4. 0 < width < datasize
  5. shiftAmount + width <= datasize

The canonical form to match FBXIL is d = ((n >> lsb) & mask1) | (d & mask2).

Given B3 IR:
Int @0 = ArgumentReg(%x0)
Int @1 = ArgumentReg(%x1)
Int @2 = lsb
Int @3 = mask1
Int @4 = mask2
Int @5 = BitAnd(@1, @3)
Int @6 = BitAnd(@0, @4))
Int @7 = ZShr(@5, @2)
Int @8 = BitOr(@7, @6)
Void@9 = Return(@8, Terminal)

Before Adding BIC:
Old optimized AIR
And mask2, %x0, %x0, @6
ExtractUnsignedBitfield %x1, lsb, width, %x1, @7
Or %x0, %x1, %x0, @8
Ret %x0, @9

After Adding BIC:
New optimized AIR
ExtractInsertBitfieldAtLowEnd %x1, lsb, width, %x0, @8
Ret64 %x0, @9


### Part B ###


The Bitfield Clear (BFC), leaving other bits unchanged, is similar to BFI which is an
alias of BFM. Given the operation:

bfc Rd, lsb, width

The equivalent pattern of this instruction is:

mask = ((1 << width) - 1) << lsb
d = d & ~mask

Since mask is a constant and B3 performs constant fold in the optimization phase, this
pattern will directly lower to the BitAnd binary operation. So, no need to match this pattern.


### Part C ###


At MacroAssembler level, the emitters are exepected to be expressed in english
(e.g. something like clearBitField for BFC). Do refactoring to rename Air opcode for
UBFX, UBFIZ, BFI, and BIC.

  • assembler/ARM64Assembler.h:

(JSC::ARM64Assembler::bfc):

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::extractUnsignedBitfield32):
(JSC::MacroAssemblerARM64::extractUnsignedBitfield64):
(JSC::MacroAssemblerARM64::insertUnsignedBitfieldInZero32):
(JSC::MacroAssemblerARM64::insertUnsignedBitfieldInZero64):
(JSC::MacroAssemblerARM64::insertBitField32):
(JSC::MacroAssemblerARM64::insertBitField64):
(JSC::MacroAssemblerARM64::clearBitField32):
(JSC::MacroAssemblerARM64::clearBitField64):
(JSC::MacroAssemblerARM64::clearBitsWithMask32):
(JSC::MacroAssemblerARM64::clearBitsWithMask64):
(JSC::MacroAssemblerARM64::orNot32):
(JSC::MacroAssemblerARM64::orNot64):
(JSC::MacroAssemblerARM64::ubfx32): Deleted.
(JSC::MacroAssemblerARM64::ubfx64): Deleted.
(JSC::MacroAssemblerARM64::ubfiz32): Deleted.
(JSC::MacroAssemblerARM64::ubfiz64): Deleted.
(JSC::MacroAssemblerARM64::bitFieldInsert32): Deleted.
(JSC::MacroAssemblerARM64::bitFieldInsert64): Deleted.

  • assembler/testmasm.cpp:

(JSC::testMultiplySignExtend32):
(JSC::testMultiplySubSignExtend32):
(JSC::testExtractUnsignedBitfield32):
(JSC::testExtractUnsignedBitfield64):
(JSC::testInsertUnsignedBitfieldInZero32):
(JSC::testInsertUnsignedBitfieldInZero64):
(JSC::testInsertBitField32):
(JSC::testInsertBitField64):
(JSC::testClearBitField32):
(JSC::testClearBitField64):
(JSC::testClearBitsWithMask32):
(JSC::testClearBitsWithMask64):
(JSC::testOrNot32):
(JSC::testOrNot64):
(JSC::testMul32SignExtend): Deleted.
(JSC::testMulSubSignExtend32): Deleted.
(JSC::testUbfx32): Deleted.
(JSC::testUbfx64): Deleted.
(JSC::testUbfiz32): Deleted.
(JSC::testUbfiz64): Deleted.
(JSC::testBitFieldInsert32): Deleted.
(JSC::testBitFieldInsert64): Deleted.

  • b3/B3LowerToAir.cpp:
  • b3/B3ReduceStrength.cpp:
  • b3/air/AirOpcode.opcodes:
  • b3/testb3.h:
  • b3/testb3_2.cpp:

(testInsertBitField32):
(testInsertBitField64):
(testBIC32):
(testBIC64):
(testOrNot32):
(testOrNot64):
(addBitTests):
(testBitFieldInsert32): Deleted.
(testBitFieldInsert64): Deleted.

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):

  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::cageWithoutUntagging):
(JSC::AssemblyHelpers::cageConditionallyAndUntag):

Location:
trunk/Source/JavaScriptCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r279343 r279362  
     12021-06-28  Yijia Huang  <yijia_huang@apple.com>
     2
     3        Add a new pattern to instruction selector to use BIC supported by ARM64
     4        https://bugs.webkit.org/show_bug.cgi?id=227202
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch includes three modifications:
     9            1. Add bit clear (BIC), or not (ORN), and extract and insert bitfield at lower end (FBXIL)
     10               to Air opcode to serve intruciton selector.
     11            2. Add bitfield clear (BFC) to MacroAssembler.
     12            4. Do refactoring - rename Air opcodes added in the previous patches.
     13
     14        ------------------
     15        ### Part A BIC ###
     16        ------------------
     17        Given the operation:
     18
     19        bic Rd, Rn, Rm
     20
     21        The BIC (Bit Clear) instruction performs an AND operation on the bits in Rn with the
     22        complements of the corresponding bits in the value of Rm. The instruction selector can
     23        utilize this to lowering certain patterns in B3 IR before further Air optimization.
     24        The equivalent patterns of this instruction are:
     25
     26        Pattern 1:
     27            d = n & (-m - 1)
     28
     29        Pattern 2:
     30            d = n & (m ^ -1)
     31
     32        In order to get benefits for complement operation, current instruction selector uses
     33        mvn instruction to lower the pattern value ^ -1. Then, a new strength reduction rule is
     34        introduced:
     35            Turn this: -value - 1
     36            Into this: value ^ -1
     37
     38        So, d = n & (m ^ -1) is selected as the canonical form.
     39
     40        Given B3 IR:
     41        Int @0 = ArgumentReg(%x0)
     42        Int @1 = ArgumentReg(%x1)
     43        Int @2 = -1
     44        Int @3 = BitXor(@1, @2)
     45        Int @4 = BitAnd(@0, @3)
     46        Void@5 = Return(@4, Terminal)
     47
     48        Before Adding BIC:
     49        // Old optimized AIR
     50        Not %x1, %x1,      @3
     51        And %x0, %x1, %x0, @4
     52        Ret %x0,           @5
     53
     54        After Adding BIC:
     55        // New optimized AIR
     56        Bic %x0, %x1, %x0, @4
     57        Ret %x0,           @5
     58
     59        ------------------
     60        ### Part A ORN ###
     61        ------------------
     62        Given the operation:
     63
     64        orn Rd, Rn, Rm
     65
     66        Bitwise OR NOT (shifted register) performs a bitwise (inclusive) OR of a register value
     67        Rn and the complement of an optionally-shifted register value Rm, and writes the result
     68        to the destination register Rd.
     69
     70        The equivalent patterns of this instruction are:
     71
     72        Pattern 1:
     73            d = n | (-m - 1)
     74
     75        Pattern 2:
     76            d = n | (m ^ -1)
     77
     78        Then, d = n | (m ^ -1) is selected as the canonical form.
     79
     80        Given B3 IR:
     81        Int @0 = ArgumentReg(%x0)
     82        Int @1 = ArgumentReg(%x1)
     83        Int @2 = -1
     84        Int @3 = BitXor(@1, @2)
     85        Int @4 = BitOr(@0, @3)
     86        Void@5 = Return(@4, Terminal)
     87
     88        Before Adding BIC:
     89        // Old optimized AIR
     90        Not %x1, %x1,      @3
     91        Or  %x0, %x1, %x0, @4
     92        Ret %x0,           @5
     93
     94        After Adding BIC:
     95        // New optimized AIR
     96        Orn %x0, %x1, %x0, @4
     97        Ret %x0,           @5
     98
     99        --------------------
     100        ### Part A FBXIL ###
     101        --------------------
     102        Given the operation:
     103
     104        bfxil Rd, Rn, lsb, width
     105
     106        Bitfield extract and insert at low end(FBXIL) copies any number of low-order bits
     107        from a source register into the same number of adjacent bits at the low end in
     108        the destination register, leaving other bits unchanged.
     109
     110        The equivalent patterns of this instruction are:
     111
     112        Pattern 1:
     113        mask1 = (1 << width) - 1
     114        mask2 = ~mask1
     115        ((n >> lsb) & mask1) | (d & mask2)
     116
     117        Pattern 2:
     118        mask1 = ((1 << width) - 1) << lsb
     119        mask2 = ~(mask1 >> lsb)
     120        ((n & mask1) >> lsb) | (d & mask2)
     121
     122        Then, introduce a strength reduction rule for easier recognization.
     123        Turn this: (v & maskShift) >> shiftAmount
     124        Into this: (v >> shiftAmount) & mask
     125
     126        with constraints:
     127        1. maskShift = mask << lsb
     128        2. mask = (1 << width) - 1
     129        3. 0 <= shiftAmount < datasize
     130        4. 0 < width < datasize
     131        5. shiftAmount + width <= datasize
     132
     133        The canonical form to match FBXIL is d = ((n >> lsb) & mask1) | (d & mask2).
     134       
     135        Given B3 IR:
     136        Int @0 = ArgumentReg(%x0)
     137        Int @1 = ArgumentReg(%x1)
     138        Int @2 = lsb
     139        Int @3 = mask1
     140        Int @4 = mask2
     141        Int @5 = BitAnd(@1, @3)
     142        Int @6 = BitAnd(@0, @4))
     143        Int @7 = ZShr(@5, @2)
     144        Int @8 = BitOr(@7, @6)
     145        Void@9 = Return(@8, Terminal)
     146
     147        Before Adding BIC:
     148        // Old optimized AIR
     149        And                      mask2, %x0,   %x0,      @6
     150        ExtractUnsignedBitfield    %x1, lsb, width, %x1, @7
     151        Or                         %x0, %x1,   %x0,      @8
     152        Ret                        %x0,                  @9
     153
     154        After Adding BIC:
     155        // New optimized AIR
     156        ExtractInsertBitfieldAtLowEnd %x1, lsb, width, %x0, @8
     157        Ret64                         %x0,                  @9
     158
     159        --------------
     160        ### Part B ###
     161        --------------
     162        The Bitfield Clear (BFC), leaving other bits unchanged, is similar to BFI which is an
     163        alias of BFM. Given the operation:
     164
     165        bfc Rd, lsb, width
     166
     167        The equivalent pattern of this instruction is:
     168
     169        mask = ((1 << width) - 1) << lsb
     170        d = d & ~mask
     171
     172        Since mask is a constant and B3 performs constant fold in the optimization phase, this
     173        pattern will directly lower to the BitAnd binary operation. So, no need to match this pattern.
     174
     175        --------------
     176        ### Part C ###
     177        --------------
     178        At MacroAssembler level, the emitters are exepected to be expressed in english
     179        (e.g. something like clearBitField for BFC). Do refactoring to rename Air opcode for
     180        UBFX, UBFIZ, BFI, and BIC.
     181
     182        * assembler/ARM64Assembler.h:
     183        (JSC::ARM64Assembler::bfc):
     184        * assembler/MacroAssemblerARM64.h:
     185        (JSC::MacroAssemblerARM64::extractUnsignedBitfield32):
     186        (JSC::MacroAssemblerARM64::extractUnsignedBitfield64):
     187        (JSC::MacroAssemblerARM64::insertUnsignedBitfieldInZero32):
     188        (JSC::MacroAssemblerARM64::insertUnsignedBitfieldInZero64):
     189        (JSC::MacroAssemblerARM64::insertBitField32):
     190        (JSC::MacroAssemblerARM64::insertBitField64):
     191        (JSC::MacroAssemblerARM64::clearBitField32):
     192        (JSC::MacroAssemblerARM64::clearBitField64):
     193        (JSC::MacroAssemblerARM64::clearBitsWithMask32):
     194        (JSC::MacroAssemblerARM64::clearBitsWithMask64):
     195        (JSC::MacroAssemblerARM64::orNot32):
     196        (JSC::MacroAssemblerARM64::orNot64):
     197        (JSC::MacroAssemblerARM64::ubfx32): Deleted.
     198        (JSC::MacroAssemblerARM64::ubfx64): Deleted.
     199        (JSC::MacroAssemblerARM64::ubfiz32): Deleted.
     200        (JSC::MacroAssemblerARM64::ubfiz64): Deleted.
     201        (JSC::MacroAssemblerARM64::bitFieldInsert32): Deleted.
     202        (JSC::MacroAssemblerARM64::bitFieldInsert64): Deleted.
     203        * assembler/testmasm.cpp:
     204        (JSC::testMultiplySignExtend32):
     205        (JSC::testMultiplySubSignExtend32):
     206        (JSC::testExtractUnsignedBitfield32):
     207        (JSC::testExtractUnsignedBitfield64):
     208        (JSC::testInsertUnsignedBitfieldInZero32):
     209        (JSC::testInsertUnsignedBitfieldInZero64):
     210        (JSC::testInsertBitField32):
     211        (JSC::testInsertBitField64):
     212        (JSC::testClearBitField32):
     213        (JSC::testClearBitField64):
     214        (JSC::testClearBitsWithMask32):
     215        (JSC::testClearBitsWithMask64):
     216        (JSC::testOrNot32):
     217        (JSC::testOrNot64):
     218        (JSC::testMul32SignExtend): Deleted.
     219        (JSC::testMulSubSignExtend32): Deleted.
     220        (JSC::testUbfx32): Deleted.
     221        (JSC::testUbfx64): Deleted.
     222        (JSC::testUbfiz32): Deleted.
     223        (JSC::testUbfiz64): Deleted.
     224        (JSC::testBitFieldInsert32): Deleted.
     225        (JSC::testBitFieldInsert64): Deleted.
     226        * b3/B3LowerToAir.cpp:
     227        * b3/B3ReduceStrength.cpp:
     228        * b3/air/AirOpcode.opcodes:
     229        * b3/testb3.h:
     230        * b3/testb3_2.cpp:
     231        (testInsertBitField32):
     232        (testInsertBitField64):
     233        (testBIC32):
     234        (testBIC64):
     235        (testOrNot32):
     236        (testOrNot64):
     237        (addBitTests):
     238        (testBitFieldInsert32): Deleted.
     239        (testBitFieldInsert64): Deleted.
     240        * ftl/FTLLowerDFGToB3.cpp:
     241        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
     242        * jit/AssemblyHelpers.cpp:
     243        (JSC::AssemblyHelpers::cageWithoutUntagging):
     244        (JSC::AssemblyHelpers::cageConditionallyAndUntag):
     245
    12462021-06-28  Mikhail R. Gadelha  <mikhail@igalia.com>
    2247
  • trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h

    r278856 r279362  
    834834
    835835    template<int datasize>
     836    ALWAYS_INLINE void bfc(RegisterID rd, int lsb, int width)
     837    {
     838        bfi<datasize>(rd, ARM64Registers::zr, lsb, width);
     839    }
     840
     841    template<int datasize>
    836842    ALWAYS_INLINE void bfi(RegisterID rd, RegisterID rn, int lsb, int width)
    837843    {
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

    r279256 r279362  
    391391    }
    392392
    393     void ubfx32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
    394     {
    395         m_assembler.ubfx<32>(dest, src, lsb.m_value, width.m_value);
    396     }
    397 
    398     void ubfx64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
    399     {
    400         m_assembler.ubfx<64>(dest, src, lsb.m_value, width.m_value);
    401     }
    402 
    403     void ubfiz32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
    404     {
    405         m_assembler.ubfiz<32>(dest, src, lsb.m_value, width.m_value);
    406     }
    407 
    408     void ubfiz64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
    409     {
    410         m_assembler.ubfiz<64>(dest, src, lsb.m_value, width.m_value);
    411     }
    412 
    413393    void and64(RegisterID src1, RegisterID src2, RegisterID dest)
    414394    {
    … …  
    467447        move(imm, getCachedDataTempRegisterIDAndInvalidate());
    468448        m_assembler.and_<64>(dest, dest, dataTempRegister);
     449    }
     450
     451    // Bit Operations:
     452    void extractUnsignedBitfield32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     453    {
     454        m_assembler.ubfx<32>(dest, src, lsb.m_value, width.m_value);
     455    }
     456
     457    void extractUnsignedBitfield64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     458    {
     459        m_assembler.ubfx<64>(dest, src, lsb.m_value, width.m_value);
     460    }
     461
     462    void insertUnsignedBitfieldInZero32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     463    {
     464        m_assembler.ubfiz<32>(dest, src, lsb.m_value, width.m_value);
     465    }
     466
     467    void insertUnsignedBitfieldInZero64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     468    {
     469        m_assembler.ubfiz<64>(dest, src, lsb.m_value, width.m_value);
     470    }
     471
     472    void insertBitField32(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     473    {
     474        m_assembler.bfi<32>(dest, source, lsb.m_value, width.m_value);
     475    }
     476
     477    void insertBitField64(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     478    {
     479        m_assembler.bfi<64>(dest, source, lsb.m_value, width.m_value);
     480    }
     481
     482    void clearBitField32(TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     483    {
     484        m_assembler.bfc<32>(dest, lsb.m_value, width.m_value);
     485    }
     486
     487    void clearBitField64(TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     488    {
     489        m_assembler.bfc<64>(dest, lsb.m_value, width.m_value);
     490    }
     491
     492    void clearBitsWithMask32(RegisterID src, RegisterID mask, RegisterID dest)
     493    {
     494        m_assembler.bic<32>(dest, src, mask);
     495    }
     496
     497    void clearBitsWithMask64(RegisterID src, RegisterID mask, RegisterID dest)
     498    {
     499        m_assembler.bic<64>(dest, src, mask);
     500    }
     501
     502    void orNot32(RegisterID src, RegisterID mask, RegisterID dest)
     503    {
     504        m_assembler.orn<32>(dest, src, mask);
     505    }
     506
     507    void orNot64(RegisterID src, RegisterID mask, RegisterID dest)
     508    {
     509        m_assembler.orn<64>(dest, src, mask);
     510    }
     511
     512    void extractInsertBitfieldAtLowEnd32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     513    {
     514        m_assembler.bfxil<32>(dest, src, lsb.m_value, width.m_value);
     515    }
     516
     517    void extractInsertBitfieldAtLowEnd64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
     518    {
     519        m_assembler.bfxil<64>(dest, src, lsb.m_value, width.m_value);
    469520    }
    470521
    … …  
    27512802        m_assembler.tst<64>(left, right);
    27522803        m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
    2753     }
    2754 
    2755     // Bit field operations:
    2756     void bitFieldInsert32(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
    2757     {
    2758         m_assembler.bfi<32>(dest, source, lsb.m_value, width.m_value);
    2759     }
    2760 
    2761     // destBitOffset is the top bit of the destination where the bits should be copied to. Zero is the lowest order bit.
    2762     void bitFieldInsert64(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)
    2763     {
    2764         m_assembler.bfi<64>(dest, source, lsb.m_value, width.m_value);
    27652804    }
    27662805
  • trunk/Source/JavaScriptCore/assembler/testmasm.cpp

    r279341 r279362  
    905905
    906906#if CPU(ARM64)
    907 void testMul32SignExtend()
     907void testMultiplySignExtend32()
    908908{
    909909    for (auto value : int32Operands()) {
    … …  
    10901090}
    10911091
    1092 void testMulSubSignExtend32()
     1092void testMultiplySubSignExtend32()
    10931093{
    10941094    // d = a - SExt32(n) *  SExt32(m)
    … …  
    11131113}
    11141114
    1115 void testUbfx32()
     1115void testExtractUnsignedBitfield32()
    11161116{
    11171117    uint32_t src = 0xf0f0f0f0;
    … …  
    11231123                    emitFunctionPrologue(jit);
    11241124
    1125                     jit.ubfx32(GPRInfo::argumentGPR0,
     1125                    jit.extractUnsignedBitfield32(GPRInfo::argumentGPR0,
    11261126                        CCallHelpers::TrustedImm32(lsb),
    11271127                        CCallHelpers::TrustedImm32(width),
    … …  
    11371137}
    11381138
    1139 void testUbfx64()
     1139void testExtractUnsignedBitfield64()
    11401140{
    11411141    uint64_t src = 0xf0f0f0f0f0f0f0f0;
    … …  
    11471147                    emitFunctionPrologue(jit);
    11481148
    1149                     jit.ubfx64(GPRInfo::argumentGPR0,
     1149                    jit.extractUnsignedBitfield64(GPRInfo::argumentGPR0,
    11501150                        CCallHelpers::TrustedImm32(lsb),
    11511151                        CCallHelpers::TrustedImm32(width),
    … …  
    11611161}
    11621162
    1163 void testUbfiz32()
     1163void testInsertUnsignedBitfieldInZero32()
    11641164{
    11651165    uint32_t src = 0xf0f0f0f0;
    … …  
    11711171                    emitFunctionPrologue(jit);
    11721172
    1173                     jit.ubfiz32(GPRInfo::argumentGPR0,
     1173                    jit.insertUnsignedBitfieldInZero32(GPRInfo::argumentGPR0,
    11741174                        CCallHelpers::TrustedImm32(lsb),
    11751175                        CCallHelpers::TrustedImm32(width),
    … …  
    11861186}
    11871187
    1188 void testUbfiz64()
     1188void testInsertUnsignedBitfieldInZero64()
    11891189{
    11901190    uint64_t src = 0xf0f0f0f0f0f0f0f0;
    … …  
    11961196                    emitFunctionPrologue(jit);
    11971197
    1198                     jit.ubfiz64(GPRInfo::argumentGPR0,
     1198                    jit.insertUnsignedBitfieldInZero64(GPRInfo::argumentGPR0,
    11991199                        CCallHelpers::TrustedImm32(lsb),
    12001200                        CCallHelpers::TrustedImm32(width),
    … …  
    12111211}
    12121212
    1213 void testBitFieldInsert32()
     1213void testInsertBitField32()
    12141214{
    12151215    uint32_t src = 0x0f0f0f0f;
    … …  
    12221222                    emitFunctionPrologue(jit);
    12231223
    1224                     jit.bitFieldInsert64(GPRInfo::argumentGPR0,
     1224                    jit.insertBitField32(GPRInfo::argumentGPR0,
    12251225                        CCallHelpers::TrustedImm32(lsb),
    12261226                        CCallHelpers::TrustedImm32(width),
    … …  
    12411241}
    12421242
    1243 void testBitFieldInsert64()
     1243void testInsertBitField64()
    12441244{
    12451245    uint64_t src = 0x0f0f0f0f0f0f0f0f;
    … …  
    12521252                    emitFunctionPrologue(jit);
    12531253
    1254                     jit.bitFieldInsert64(GPRInfo::argumentGPR0,
     1254                    jit.insertBitField64(GPRInfo::argumentGPR0,
    12551255                        CCallHelpers::TrustedImm32(lsb),
    12561256                        CCallHelpers::TrustedImm32(width),
    … …  
    12681268            }
    12691269        }
     1270    }
     1271}
     1272
     1273void testExtractInsertBitfieldAtLowEnd32()
     1274{
     1275    uint32_t src = 0xf0f0f0f0;
     1276    uint32_t dst = 0x0f0f0f0f;
     1277    Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 };
     1278    for (auto lsb : imms) {
     1279        for (auto width : imms) {
     1280            if (lsb >= 0 && width > 0 && lsb + width < 32) {
     1281                auto bfxil32 = compile([=] (CCallHelpers& jit) {
     1282                    emitFunctionPrologue(jit);
     1283
     1284                    jit.extractInsertBitfieldAtLowEnd32(GPRInfo::argumentGPR0,
     1285                        CCallHelpers::TrustedImm32(lsb),
     1286                        CCallHelpers::TrustedImm32(width),
     1287                        GPRInfo::argumentGPR1);
     1288                    jit.move(GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
     1289
     1290                    emitFunctionEpilogue(jit);
     1291                    jit.ret();
     1292                });
     1293                uint32_t mask1 = (1U << width) - 1U;
     1294                uint32_t mask2 = ~mask1;
     1295                uint32_t rhs = invoke<uint32_t>(bfxil32, src, dst);
     1296                uint32_t lhs = ((src >> lsb) & mask1) | (dst & mask2);
     1297                CHECK_EQ(rhs, lhs);
     1298            }
     1299        }
     1300    }
     1301}
     1302
     1303void testExtractInsertBitfieldAtLowEnd64()
     1304{
     1305    uint64_t src = 0x0f0f0f0f0f0f0f0f;
     1306    uint64_t dst = 0xf0f0f0f0f0f0f0f0;
     1307    Vector<uint64_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 };
     1308    for (auto lsb : imms) {
     1309        for (auto width : imms) {
     1310            if (lsb >= 0 && width > 0 && lsb + width < 64) {
     1311                auto bfxil64 = compile([=] (CCallHelpers& jit) {
     1312                    emitFunctionPrologue(jit);
     1313
     1314                    jit.extractInsertBitfieldAtLowEnd64(GPRInfo::argumentGPR0,
     1315                        CCallHelpers::TrustedImm32(lsb),
     1316                        CCallHelpers::TrustedImm32(width),
     1317                        GPRInfo::argumentGPR1);
     1318                    jit.move(GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
     1319
     1320                    emitFunctionEpilogue(jit);
     1321                    jit.ret();
     1322                });
     1323                uint64_t mask1 = (1ULL << width) - 1ULL;
     1324                uint64_t mask2 = ~mask1;
     1325                uint64_t rhs = invoke<uint64_t>(bfxil64, src, dst);
     1326                uint64_t lhs = ((src >> lsb) & mask1) | (dst & mask2);
     1327                CHECK_EQ(rhs, lhs);
     1328            }
     1329        }
     1330    }
     1331}
     1332
     1333void testClearBitField32()
     1334{
     1335    uint32_t src = std::numeric_limits<uint32_t>::max();
     1336    Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 };
     1337    for (auto lsb : imms) {
     1338        for (auto width : imms) {
     1339            if (lsb >= 0 && width > 0 && lsb + width < 32) {
     1340                auto bfc32 = compile([=] (CCallHelpers& jit) {
     1341                    emitFunctionPrologue(jit);
     1342
     1343                    jit.clearBitField32(CCallHelpers::TrustedImm32(lsb), CCallHelpers::TrustedImm32(width), GPRInfo::argumentGPR0);
     1344                    jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR);
     1345
     1346                    emitFunctionEpilogue(jit);
     1347                    jit.ret();
     1348                });
     1349                uint32_t mask = ((1U << width) - 1U) << lsb;
     1350                uint32_t rhs = invoke<uint32_t>(bfc32, src);
     1351                uint32_t lhs = src & ~mask;
     1352                CHECK_EQ(rhs, lhs);
     1353            }
     1354        }
     1355    }
     1356}
     1357
     1358void testClearBitField64()
     1359{
     1360    uint64_t src = std::numeric_limits<uint64_t>::max();
     1361    Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 };
     1362    for (auto lsb : imms) {
     1363        for (auto width : imms) {
     1364            if (lsb >= 0 && width > 0 && lsb + width < 32) {
     1365                auto bfc64 = compile([=] (CCallHelpers& jit) {
     1366                    emitFunctionPrologue(jit);
     1367
     1368                    jit.clearBitField64(CCallHelpers::TrustedImm32(lsb), CCallHelpers::TrustedImm32(width), GPRInfo::argumentGPR0);
     1369                    jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR);
     1370
     1371                    emitFunctionEpilogue(jit);
     1372                    jit.ret();
     1373                });
     1374                uint64_t mask = ((1ULL << width) - 1ULL) << lsb;
     1375                uint64_t rhs = invoke<uint64_t>(bfc64, src);
     1376                uint64_t lhs = src & ~mask;
     1377                CHECK_EQ(rhs, lhs);
     1378            }
     1379        }
     1380    }
     1381}
     1382
     1383void testClearBitsWithMask32()
     1384{
     1385    auto test = compile([] (CCallHelpers& jit) {
     1386        emitFunctionPrologue(jit);
     1387
     1388        jit.clearBitsWithMask32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
     1389
     1390        emitFunctionEpilogue(jit);
     1391        jit.ret();
     1392    });
     1393
     1394    for (auto mask : int32Operands()) {
     1395        uint32_t src = std::numeric_limits<uint32_t>::max();
     1396        CHECK_EQ(invoke<uint32_t>(test, src, mask), (src & ~mask));
     1397        CHECK_EQ(invoke<uint32_t>(test, 0U, mask), 0U);
     1398    }
     1399}
     1400
     1401void testClearBitsWithMask64()
     1402{
     1403    auto test = compile([] (CCallHelpers& jit) {
     1404        emitFunctionPrologue(jit);
     1405
     1406        jit.clearBitsWithMask64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
     1407
     1408        emitFunctionEpilogue(jit);
     1409        jit.ret();
     1410    });
     1411
     1412    for (auto mask : int64Operands()) {
     1413        uint64_t src = std::numeric_limits<uint64_t>::max();
     1414        CHECK_EQ(invoke<uint64_t>(test, src, mask), (src & ~mask));
     1415        CHECK_EQ(invoke<uint64_t>(test, 0ULL, mask), 0ULL);
     1416    }
     1417}
     1418
     1419void testOrNot32()
     1420{
     1421    auto test = compile([] (CCallHelpers& jit) {
     1422        emitFunctionPrologue(jit);
     1423
     1424        jit.orNot32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
     1425
     1426        emitFunctionEpilogue(jit);
     1427        jit.ret();
     1428    });
     1429
     1430    for (auto mask : int32Operands()) {
     1431        int32_t src = std::numeric_limits<uint32_t>::max();
     1432        CHECK_EQ(invoke<int32_t>(test, src, mask), (src | ~mask));
     1433        CHECK_EQ(invoke<int32_t>(test, 0U, mask), ~mask);
     1434    }
     1435}
     1436
     1437void testOrNot64()
     1438{
     1439    auto test = compile([] (CCallHelpers& jit) {
     1440        emitFunctionPrologue(jit);
     1441
     1442        jit.orNot64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR);
     1443
     1444        emitFunctionEpilogue(jit);
     1445        jit.ret();
     1446    });
     1447
     1448    for (auto mask : int64Operands()) {
     1449        int64_t src = std::numeric_limits<uint64_t>::max();
     1450        CHECK_EQ(invoke<int64_t>(test, src, mask), (src | ~mask));
     1451        CHECK_EQ(invoke<int64_t>(test, 0ULL, mask), ~mask);
    12701452    }
    12711453}
    … …  
    34263608    RUN(testLoadStorePair64Int64());
    34273609    RUN(testLoadStorePair64Double());
    3428     RUN(testMul32SignExtend());
    3429     RUN(testMultiplyAddSignExtend32Left());
    3430     RUN(testMultiplyAddSignExtend32Right());
     3610    RUN(testMultiplySignExtend32());
     3611
    34313612    RUN(testSub32Args());
    34323613    RUN(testSub32Imm());
    … …  
    34363617    RUN(testSub64Imm64());
    34373618    RUN(testSub64ArgImm64());
    3438     RUN(testMulSubSignExtend32());
    3439     RUN(testUbfx32());
    3440     RUN(testUbfx64());
    3441     RUN(testUbfiz32());
    3442     RUN(testUbfiz64());
    3443     RUN(testBitFieldInsert32());
    3444     RUN(testBitFieldInsert64());
     3619
     3620    RUN(testMultiplyAddSignExtend32Left());
     3621    RUN(testMultiplyAddSignExtend32Right());
     3622    RUN(testMultiplySubSignExtend32());
     3623
     3624    RUN(testExtractUnsignedBitfield32());
     3625    RUN(testExtractUnsignedBitfield64());
     3626    RUN(testInsertUnsignedBitfieldInZero32());
     3627    RUN(testInsertUnsignedBitfieldInZero64());
     3628    RUN(testInsertBitField32());
     3629    RUN(testInsertBitField64());
     3630    RUN(testExtractInsertBitfieldAtLowEnd32());
     3631    RUN(testExtractInsertBitfieldAtLowEnd64());
     3632    RUN(testClearBitField32());
     3633    RUN(testClearBitField64());
     3634    RUN(testClearBitsWithMask32());
     3635    RUN(testClearBitsWithMask64());
     3636
     3637    RUN(testOrNot32());
     3638    RUN(testOrNot64());
    34453639#endif
    34463640
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r279249 r279362  
    27652765            // Where: mask = (1 << width) - 1
    27662766            auto tryAppendUBFX = [&] () -> bool {
    2767                 Air::Opcode opcode = opcodeForType(Ubfx32, Ubfx64, m_value->type());
     2767                Air::Opcode opcode = opcodeForType(ExtractUnsignedBitfield32, ExtractUnsignedBitfield64, m_value->type());
    27682768                if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp))
    27692769                    return false;
    … …  
    27812781                    return false;
    27822782                uint64_t width = WTF::bitCount(mask);
    2783                 uint64_t datasize = opcode == Ubfx32 ? 32 : 64;
     2783                uint64_t datasize = opcode == ExtractUnsignedBitfield32 ? 32 : 64;
    27842784                if (lsb + width > datasize)
    27852785                    return false;
    … …  
    27932793                return;
    27942794
     2795            // BIC Pattern: d = n & (m ^ -1)
     2796            auto tryAppendBIC = [&] (Value* left, Value* right) -> bool {
     2797                Air::Opcode opcode = opcodeForType(ClearBitsWithMask32, ClearBitsWithMask64, m_value->type());
     2798                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Tmp))
     2799                    return false;
     2800                if (right->opcode() != BitXor || !canBeInternal(right))
     2801                    return false;
     2802
     2803                Value* nValue = left;
     2804                Value* mValue = right->child(0);
     2805                Value* minusOne = right->child(1);
     2806                if (m_locked.contains(nValue) || m_locked.contains(mValue) || !minusOne->hasInt() || !minusOne->isInt(-1))
     2807                    return false;
     2808
     2809                append(opcode, tmp(nValue), tmp(mValue), tmp(m_value));
     2810                commitInternal(right);
     2811                return true;
     2812            };
     2813
     2814            if (tryAppendBIC(left, right) || tryAppendBIC(right, left))
     2815                return;
     2816
    27952817            appendBinOp<And32, And64, AndDouble, AndFloat, Commutative>(left, right);
    27962818            return;
    … …  
    28052827            //        mask2 = ~(mask1 << lsb)
    28062828            auto tryAppendBFI = [&] (Value* left, Value* right) -> bool {
    2807                 Air::Opcode opcode = opcodeForType(BitFieldInsert32, BitFieldInsert64, m_value->type());
     2829                Air::Opcode opcode = opcodeForType(InsertBitField32, InsertBitField64, m_value->type());
    28082830                if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp))
    28092831                    return false;
    … …  
    28292851                if (!mask1 || mask1 & (mask1 + 1))
    28302852                    return false;
    2831                 uint64_t datasize = opcode == BitFieldInsert32 ? 32 : 64;
     2853                uint64_t datasize = opcode == InsertBitField32 ? 32 : 64;
    28322854                uint64_t width = WTF::bitCount(mask1);
    28332855                if (lsb + width > datasize)
    … …  
    28582880                return;
    28592881
     2882            // BFXIL Pattern: d = ((n >> lsb) & mask1) | (d & mask2)
     2883            // Where: mask1 = ((1 << width) - 1)
     2884            //        mask2 = ~mask1
     2885            auto tryAppendBFXIL = [&] (Value* left, Value* right) -> bool {
     2886                Air::Opcode opcode = opcodeForType(ExtractInsertBitfieldAtLowEnd32, ExtractInsertBitfieldAtLowEnd64, m_value->type());
     2887                if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp))
     2888                    return false;
     2889                if (left->opcode() != BitAnd || !canBeInternal(left))
     2890                    return false;
     2891                if (left->child(0)->opcode() != ZShr || !canBeInternal(left->child(0)))
     2892                    return false;
     2893                if (right->opcode() != BitAnd || !canBeInternal(right))
     2894                    return false;
     2895
     2896                Value* nValue = left->child(0)->child(0);
     2897                Value* maskValue1 = left->child(1);
     2898                Value* lsbValue = left->child(0)->child(1);
     2899                Value* dValue = right->child(0);
     2900                Value* maskValue2 = right->child(1);
     2901                if (m_locked.contains(nValue) || m_locked.contains(dValue))
     2902                    return false;
     2903                if (!maskValue1->hasInt() || !imm(lsbValue) || lsbValue->asInt() < 0 || !maskValue2->hasInt())
     2904                    return false;
     2905
     2906                uint64_t lsb = lsbValue->asInt();
     2907                uint64_t mask1 = maskValue1->asInt();
     2908                if (!mask1 || mask1 & (mask1 + 1))
     2909                    return false;
     2910                uint64_t width = WTF::bitCount(mask1);
     2911                uint64_t datasize = opcode == ExtractInsertBitfieldAtLowEnd32 ? 32 : 64;
     2912                if (lsb + width > datasize)
     2913                    return false;
     2914                uint64_t mask2 = maskValue2->asInt();
     2915
     2916                auto isValidMask2 = [&] () -> bool {
     2917                    uint64_t mask = mask1 ^ mask2;
     2918                    uint64_t lowerSet = 0xffffffff;
     2919                    uint64_t fullSet = 0xffffffffffffffff;
     2920                    return datasize == 32 ? !((mask & lowerSet) ^ lowerSet) : !(mask ^ fullSet);
     2921                };
     2922
     2923                if (!isValidMask2())
     2924                    return false;
     2925
     2926                Tmp result = tmp(m_value);
     2927                append(relaxedMoveForType(m_value->type()), tmp(dValue), result);
     2928                append(opcode, tmp(nValue), imm(lsbValue), imm(width), result);
     2929                commitInternal(left->child(0));
     2930                commitInternal(left);
     2931                commitInternal(right);
     2932                return true;
     2933            };
     2934
     2935            if (tryAppendBFXIL(left, right) || tryAppendBFXIL(right, left))
     2936                return;
     2937
     2938            // ORN Pattern: d = n | (m ^ -1)
     2939            auto tryAppendORN = [&] (Value* left, Value* right) -> bool {
     2940                Air::Opcode opcode = opcodeForType(OrNot32, OrNot64, m_value->type());
     2941                if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Tmp))
     2942                    return false;
     2943                if (right->opcode() != BitXor || !canBeInternal(right))
     2944                    return false;
     2945
     2946                Value* nValue = left;
     2947                Value* mValue = right->child(0);
     2948                Value* minusOne = right->child(1);
     2949                if (m_locked.contains(nValue) || m_locked.contains(mValue) || !minusOne->hasInt() || !minusOne->isInt(-1))
     2950                    return false;
     2951
     2952                append(opcode, tmp(nValue), tmp(mValue), tmp(m_value));
     2953                commitInternal(right);
     2954                return true;
     2955            };
     2956
     2957            if (tryAppendORN(left, right) || tryAppendORN(right, left))
     2958                return;
     2959
    28602960            appendBinOp<Or32, Or64, OrDouble, OrFloat, Commutative>(left, right);
    28612961            return;
    … …  
    29003000            // Where: mask = (1 << width) - 1
    29013001            auto tryAppendUBFZ = [&] () -> bool {
    2902                 Air::Opcode opcode = opcodeForType(Ubfiz32, Ubfiz64, m_value->type());
     3002                Air::Opcode opcode = opcodeForType(InsertUnsignedBitfieldInZero32, InsertUnsignedBitfieldInZero64, m_value->type());
    29033003                if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp))
    29043004                    return false;
    … …  
    29163016                    return false;
    29173017                uint64_t width = WTF::bitCount(mask);
    2918                 uint64_t datasize = opcode == Ubfiz32 ? 32 : 64;
     3018                uint64_t datasize = opcode == InsertUnsignedBitfieldInZero32 ? 32 : 64;
    29193019                if (lsb + width > datasize)
    29203020                    return false;
    … …  
    29433043
    29443044        case ZShr: {
    2945             appendShift<Urshift32, Urshift64>(m_value->child(0), m_value->child(1));
     3045            Value* left = m_value->child(0);
     3046            Value* right = m_value->child(1);
     3047
     3048            appendShift<Urshift32, Urshift64>(left, right);
    29463049            return;
    29473050        }
  • trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp

    r279193 r279362  
    628628
    629629            if (m_value->isInteger()) {
     630                // Turn this: Sub(Neg(value), 1)
     631                // Into this: BitXor(value, -1)
     632                if (m_value->child(0)->opcode() == Neg && m_value->child(1)->isInt(1)) {
     633                    Value* minusOne;
     634                    if (m_value->child(0)->child(0)->type() == Int32)
     635                        minusOne = m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), -1);
     636                    else
     637                        minusOne = m_insertionSet.insert<Const64Value>(m_index, m_value->origin(), -1);
     638                    replaceWithNew<Value>(BitXor, m_value->origin(), m_value->child(0)->child(0), minusOne);
     639                    break;
     640                }
     641
    630642                // Turn this: Sub(value, constant)
    631643                // Into this: Add(value, -constant)
    … …  
    10611073
    10621074            // Turn this: BitAnd(Shl(value, shiftAmount), maskShift)
     1075            // Into this: Shl(BitAnd(value, mask), shiftAmount)
    10631076            // Conditions:
    10641077            // 1. maskShift = mask << shiftAmount
    … …  
    10671080            // 4. 0 < width < datasize
    10681081            // 5. shiftAmount + width <= datasize
    1069             // Into this: Shl(BitAnd(value, mask), shiftAmount)
    10701082            if (m_value->child(0)->opcode() == Shl
    10711083                && m_value->child(0)->child(1)->hasInt()
    … …  
    14231435                replaceWithNewValue(constant);
    14241436                break;
     1437            }
     1438
     1439            // Turn this: ZShr(BitAnd(value, maskShift), shiftAmount)
     1440            // Into this: BitAnd(ZShr(value, shiftAmount), mask)
     1441            // Conditions:
     1442            // 1. maskShift = mask << shiftAmount
     1443            // 2. mask = (1 << width) - 1
     1444            // 3. 0 <= shiftAmount < datasize
     1445            // 4. 0 < width < datasize
     1446            // 5. shiftAmount + width <= datasize
     1447            if (m_value->child(0)->opcode() == BitAnd
     1448                && m_value->child(0)->child(1)->hasInt()
     1449                && m_value->child(1)->hasInt()
     1450                && m_value->child(1)->asInt() >= 0) {
     1451                uint64_t shiftAmount = m_value->child(1)->asInt();
     1452                uint64_t maskShift = m_value->child(0)->child(1)->asInt();
     1453                uint64_t maskShiftAmount = WTF::countTrailingZeros(maskShift);
     1454                uint64_t mask = maskShift >> maskShiftAmount;
     1455                uint64_t width = WTF::bitCount(mask);
     1456                uint64_t datasize = m_value->child(0)->child(0)->type() == Int64 ? 64 : 32;
     1457                bool isValidShiftAmount = maskShiftAmount == shiftAmount && shiftAmount < datasize;
     1458                bool isValidMask = mask && !(mask & (mask + 1)) && width < datasize;
     1459                if (isValidShiftAmount && isValidMask && shiftAmount + width <= datasize) {
     1460                    Value* maskValue;
     1461                    if (datasize == 32)
     1462                        maskValue = m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), mask);
     1463                    else
     1464                        maskValue = m_insertionSet.insert<Const64Value>(m_index, m_value->origin(), mask);
     1465                    Value* shiftValue = m_insertionSet.insert<Value>(m_index, ZShr, m_value->origin(), m_value->child(0)->child(0), m_value->child(1));
     1466                    replaceWithNew<Value>(BitAnd, m_value->origin(), shiftValue, maskValue);
     1467                    break;
     1468                }
    14251469            }
    14261470
  • trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes

    r279249 r279362  
    364364    x86: Imm, Index
    365365
    366 arm64: Ubfx32 U:G:32, U:G:32, U:G:32, ZD:G:32
    367     Tmp, Imm, Imm, Tmp
    368 
    369 arm64: Ubfx64 U:G:64, U:G:32, U:G:32, D:G:64
    370     Tmp, Imm, Imm, Tmp
    371 
    372 arm64: Ubfiz32 U:G:32, U:G:32, U:G:32, ZD:G:32
    373     Tmp, Imm, Imm, Tmp
    374 
    375 arm64: Ubfiz64 U:G:64, U:G:32, U:G:32, D:G:64
    376     Tmp, Imm, Imm, Tmp
    377 
    378 arm64: BitFieldInsert32 U:G:32, U:G:32, U:G:32, ZD:G:32
    379     Tmp, Imm, Imm, Tmp
    380 
    381 arm64: BitFieldInsert64 U:G:64, U:G:32, U:G:32, D:G:64
    382     Tmp, Imm, Imm, Tmp
    383 
    38436664: And64 U:G:64, U:G:64, D:G:64
    385367    Tmp, Tmp, Tmp
    … …  
    831813    Tmp, Index
    832814
     815arm64: ExtractUnsignedBitfield32 U:G:32, U:G:32, U:G:32, ZD:G:32
     816    Tmp, Imm, Imm, Tmp
     817
     818arm64: ExtractUnsignedBitfield64 U:G:64, U:G:32, U:G:32, D:G:64
     819    Tmp, Imm, Imm, Tmp
     820
     821arm64: InsertUnsignedBitfieldInZero32 U:G:32, U:G:32, U:G:32, ZD:G:32
     822    Tmp, Imm, Imm, Tmp
     823
     824arm64: InsertUnsignedBitfieldInZero64 U:G:64, U:G:32, U:G:32, D:G:64
     825    Tmp, Imm, Imm, Tmp
     826
     827arm64: InsertBitField32 U:G:32, U:G:32, U:G:32, ZD:G:32
     828    Tmp, Imm, Imm, Tmp
     829
     830arm64: InsertBitField64 U:G:64, U:G:32, U:G:32, D:G:64
     831    Tmp, Imm, Imm, Tmp
     832
     833arm64: ClearBitField32 U:G:32, U:G:32, ZD:G:32
     834    Imm, Imm, Tmp
     835
     836arm64: ClearBitField64 U:G:32, U:G:32, D:G:64
     837    Imm, Imm, Tmp
     838
     839arm64: ClearBitsWithMask32 U:G:32, U:G:32, ZD:G:32
     840    Tmp, Tmp, Tmp
     841
     842arm64: ClearBitsWithMask64 U:G:64, U:G:64, D:G:64
     843    Tmp, Tmp, Tmp
     844
     845arm64: OrNot32 U:G:32, U:G:32, ZD:G:32
     846    Tmp, Tmp, Tmp
     847
     848arm64: OrNot64 U:G:64, U:G:64, D:G:64
     849    Tmp, Tmp, Tmp
     850
     851arm64: ExtractInsertBitfieldAtLowEnd32 U:G:32, U:G:32, U:G:32, ZD:G:32
     852    Tmp, Imm, Imm, Tmp
     853
     854arm64: ExtractInsertBitfieldAtLowEnd64 U:G:64, U:G:32, U:G:32, D:G:64
     855    Tmp, Imm, Imm, Tmp
     856
    833857# The first operand is rax.
    834858# FIXME: This formulation means that the boolean result cannot be put in eax, even though all users
  • trunk/Source/JavaScriptCore/b3/testb3.h

    r279249 r279362  
    429429void testUbfiz64ShiftAnd();
    430430void testUbfiz64AndShift();
    431 void testBitFieldInsert32();
    432 void testBitFieldInsert64();
     431void testInsertBitField32();
     432void testInsertBitField64();
     433void testExtractInsertBitfieldAtLowEnd32();
     434void testExtractInsertBitfieldAtLowEnd64();
     435void testBIC32();
     436void testBIC64();
     437void testOrNot32();
     438void testOrNot64();
    433439void testBitAndZeroShiftRightArgImmMask32();
    434440void testBitAndZeroShiftRightArgImmMask64();
  • trunk/Source/JavaScriptCore/b3/testb3_2.cpp

    r279249 r279362  
    31593159}
    31603160
    3161 void testBitFieldInsert32()
     3161void testInsertBitField32()
    31623162{
    31633163    if (JSC::Options::defaultB3OptLevel() < 2)
    … …  
    31653165    uint32_t d = 0xf0f0f0f0;
    31663166    uint32_t n = 0xffffffff;
    3167     Vector<uint32_t> lsbs = { 1, 2, 14, 30, 30 };
     3167    Vector<uint32_t> lsbs = { 2, 2, 14, 30, 30 };
    31683168    Vector<uint32_t> widths = { 30, 3, 17, 1, 2 };
    31693169
    … …  
    32373237}
    32383238
    3239 void testBitFieldInsert64()
     3239void testInsertBitField64()
    32403240{
    32413241    if (JSC::Options::defaultB3OptLevel() < 2)
    … …  
    32433243    uint64_t d = 0xf0f0f0f0f0f0f0f0;
    32443244    uint64_t n = 0xffffffffffffffff;
    3245     Vector<uint64_t> lsbs = { 1, 30, 14, 62, 62 };
     3245    Vector<uint64_t> lsbs = { 2, 30, 14, 62, 62 };
    32463246    Vector<uint64_t> widths = { 62, 33, 17, 1, 2 };
    32473247
    … …  
    33043304        CHECK(test1(lsb, mask1, mask2) == (((n & mask1) << lsb) | (d & mask2)));
    33053305        CHECK(test2(lsb, mask1, mask2) == ((d & mask2) | ((n & mask1) << lsb)));
     3306    }
     3307}
     3308
     3309void testExtractInsertBitfieldAtLowEnd32()
     3310{
     3311    if (JSC::Options::defaultB3OptLevel() < 2)
     3312        return;
     3313    uint32_t d = 0xf0f0f0f0;
     3314    uint32_t n = 0xffffffff;
     3315    Vector<uint32_t> lsbs = { 1, 10, 14, 30 };
     3316    Vector<uint32_t> widths = { 30, 11, 17, 1 };
     3317
     3318    // BFXIL Pattern: d = ((n >> lsb) & mask1) | (d & mask2)
     3319    // Where: mask1 = ((1 << width) - 1)
     3320    //        mask2 = ~mask1
     3321    auto test1 = [&] (uint32_t lsb, uint32_t mask1, uint32_t mask2) -> uint32_t {
     3322        Procedure proc;
     3323        BasicBlock* root = proc.addBlock();
     3324
     3325        Value* dValue = root->appendNew<Value>(
     3326            proc, Trunc, Origin(),
     3327            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3328        Value* nValue = root->appendNew<Value>(
     3329            proc, Trunc, Origin(),
     3330            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     3331        Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb);
     3332        Value* maskValue1 = root->appendNew<Const32Value>(proc, Origin(), mask1);
     3333        Value* maskValue2 = root->appendNew<Const32Value>(proc, Origin(), mask2);
     3334
     3335        Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), nValue, lsbValue);
     3336        Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), shiftValue, maskValue1);
     3337        Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2);
     3338        root->appendNewControlValue(
     3339            proc, Return, Origin(),
     3340            root->appendNew<Value>(proc, BitOr, Origin(), leftAndValue, rightAndValue));
     3341
     3342        auto code = compileProc(proc);
     3343        if (isARM64())
     3344            checkUsesInstruction(*code, "bfxil");
     3345        return invoke<uint32_t>(*code, d, n);
     3346    };
     3347
     3348    for (size_t i = 0; i < lsbs.size(); ++i) {
     3349        uint32_t lsb = lsbs.at(i);
     3350        uint32_t mask1 = (1U << widths.at(i)) - 1U;
     3351        uint32_t mask2 = ~mask1;
     3352        CHECK(test1(lsb, mask1, mask2) == (((n >> lsb) & mask1) | (d & mask2)));
     3353    }
     3354
     3355    // BFXIL Pattern: d = ((n & mask1) >> lsb) | (d & mask2)
     3356    // Where: mask1 = ((1 << width) - 1) << lsb
     3357    //        mask2 = ~(mask1 >> lsb)
     3358    auto test2 = [&] (uint32_t lsb, uint32_t mask1, uint32_t mask2) -> uint32_t {
     3359        Procedure proc;
     3360        BasicBlock* root = proc.addBlock();
     3361
     3362        Value* dValue = root->appendNew<Value>(
     3363            proc, Trunc, Origin(),
     3364            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3365        Value* nValue = root->appendNew<Value>(
     3366            proc, Trunc, Origin(),
     3367            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     3368        Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb);
     3369        Value* maskValue1 = root->appendNew<Const32Value>(proc, Origin(), mask1);
     3370        Value* maskValue2 = root->appendNew<Const32Value>(proc, Origin(), mask2);
     3371
     3372        Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), nValue, maskValue1);
     3373        Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2);
     3374        Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), leftAndValue, lsbValue);
     3375        root->appendNewControlValue(
     3376            proc, Return, Origin(),
     3377            root->appendNew<Value>(proc, BitOr, Origin(), shiftValue, rightAndValue));
     3378
     3379        auto code = compileProc(proc);
     3380        if (isARM64())
     3381            checkUsesInstruction(*code, "bfxil");
     3382        return invoke<uint32_t>(*code, d, n);
     3383    };
     3384
     3385    for (size_t i = 0; i < lsbs.size(); ++i) {
     3386        uint32_t lsb = lsbs.at(i);
     3387        uint32_t mask1 = ((1U << widths.at(i)) - 1U) << lsb;
     3388        uint32_t mask2 = ~(mask1 >> lsb);
     3389        CHECK(test2(lsb, mask1, mask2) == (((n & mask1) >> lsb) | (d & mask2)));
     3390    }
     3391}
     3392
     3393void testExtractInsertBitfieldAtLowEnd64()
     3394{
     3395    if (JSC::Options::defaultB3OptLevel() < 2)
     3396        return;
     3397    uint64_t d = 0xf0f0f0f0f0f0f0f0;
     3398    uint64_t n = 0xffffffffffffffff;
     3399    Vector<uint64_t> lsbs = { 1, 30, 14, 62 };
     3400    Vector<uint64_t> widths = { 62, 33, 17, 1 };
     3401
     3402    // BFXIL Pattern: d = ((n >> lsb) & mask1) | (d & mask2)
     3403    // Where: mask1 = ((1 << width) - 1)
     3404    //        mask2 = ~mask1
     3405    auto test1 = [&] (uint64_t lsb, uint64_t mask1, uint64_t mask2) -> uint64_t {
     3406        Procedure proc;
     3407        BasicBlock* root = proc.addBlock();
     3408
     3409        Value* dValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3410        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3411        Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb);
     3412        Value* maskValue1 = root->appendNew<Const64Value>(proc, Origin(), mask1);
     3413        Value* maskValue2 = root->appendNew<Const64Value>(proc, Origin(), mask2);
     3414
     3415        Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), nValue, lsbValue);
     3416        Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), shiftValue, maskValue1);
     3417        Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2);
     3418        root->appendNewControlValue(
     3419            proc, Return, Origin(),
     3420            root->appendNew<Value>(proc, BitOr, Origin(), leftAndValue, rightAndValue));
     3421
     3422        auto code = compileProc(proc);
     3423        if (isARM64())
     3424            checkUsesInstruction(*code, "bfxil");
     3425        return invoke<uint64_t>(*code, d, n);
     3426    };
     3427
     3428    for (size_t i = 0; i < lsbs.size(); ++i) {
     3429        uint64_t lsb = lsbs.at(i);
     3430        uint64_t mask1 = (1ULL << widths.at(i)) - 1ULL;
     3431        uint64_t mask2 = ~mask1;
     3432        CHECK(test1(lsb, mask1, mask2) == (((n >> lsb) & mask1) | (d & mask2)));
     3433    }
     3434
     3435    // BFXIL Pattern: d = ((n & mask1) >> lsb) | (d & mask2)
     3436    // Where: mask1 = ((1 << width) - 1) << lsb
     3437    //        mask2 = ~(mask1 >> lsb)
     3438    auto test2 = [&] (uint64_t lsb, uint64_t mask1, uint64_t mask2) -> uint64_t {
     3439        Procedure proc;
     3440        BasicBlock* root = proc.addBlock();
     3441
     3442        Value* dValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3443        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3444        Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb);
     3445        Value* maskValue1 = root->appendNew<Const64Value>(proc, Origin(), mask1);
     3446        Value* maskValue2 = root->appendNew<Const64Value>(proc, Origin(), mask2);
     3447
     3448        Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), nValue, maskValue1);
     3449        Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2);
     3450        Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), leftAndValue, lsbValue);
     3451        root->appendNewControlValue(
     3452            proc, Return, Origin(),
     3453            root->appendNew<Value>(proc, BitOr, Origin(), shiftValue, rightAndValue));
     3454
     3455        auto code = compileProc(proc);
     3456        if (isARM64())
     3457            checkUsesInstruction(*code, "bfxil");
     3458        return invoke<uint64_t>(*code, d, n);
     3459    };
     3460
     3461    for (size_t i = 0; i < lsbs.size(); ++i) {
     3462        uint64_t lsb = lsbs.at(i);
     3463        uint64_t mask1 = ((1ULL << widths.at(i)) - 1ULL) << lsb;
     3464        uint64_t mask2 = ~(mask1 >> lsb);
     3465        CHECK(test2(lsb, mask1, mask2) == (((n & mask1) >> lsb) | (d & mask2)));
     3466    }
     3467}
     3468
     3469void testBIC32()
     3470{
     3471    if (JSC::Options::defaultB3OptLevel() < 2)
     3472        return;
     3473
     3474    // Test Pattern: d = n & (-m - 1)
     3475    auto test1 = [&] (int32_t n, int32_t m) -> int32_t {
     3476        Procedure proc;
     3477        BasicBlock* root = proc.addBlock();
     3478
     3479        Value* nValue = root->appendNew<Value>(
     3480            proc, Trunc, Origin(),
     3481            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3482        Value* mValue = root->appendNew<Value>(
     3483            proc, Trunc, Origin(),
     3484            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     3485        Value* const1 = root->appendNew<Const32Value>(proc, Origin(), 1);
     3486
     3487        Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue);
     3488        Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1);
     3489        root->appendNewControlValue(
     3490            proc, Return, Origin(),
     3491            root->appendNew<Value>(proc, BitAnd, Origin(), nValue, subValue));
     3492
     3493        auto code = compileProc(proc);
     3494        if (isARM64())
     3495            checkUsesInstruction(*code, "bic");
     3496        return invoke<int32_t>(*code, n, m);
     3497    };
     3498
     3499    // Test Pattern: d = n & (m ^ -1)
     3500    auto test2 = [&] (int32_t n, int32_t m) -> int32_t {
     3501        Procedure proc;
     3502        BasicBlock* root = proc.addBlock();
     3503
     3504        Value* nValue = root->appendNew<Value>(
     3505            proc, Trunc, Origin(),
     3506            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3507        Value* mValue = root->appendNew<Value>(
     3508            proc, Trunc, Origin(),
     3509            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     3510        Value* minusOneValue = root->appendNew<Const32Value>(proc, Origin(), -1);
     3511
     3512        Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue);
     3513        root->appendNewControlValue(
     3514            proc, Return, Origin(),
     3515            root->appendNew<Value>(proc, BitAnd, Origin(), nValue, xorValue));
     3516
     3517        auto code = compileProc(proc);
     3518        if (isARM64())
     3519            checkUsesInstruction(*code, "bic");
     3520        return invoke<int32_t>(*code, n, m);
     3521    };
     3522
     3523    for (auto n : int32Operands()) {
     3524        for (auto m : int32Operands()) {
     3525            CHECK(test1(n.value, m.value) == (n.value & (-m.value - 1)));
     3526            CHECK(test2(n.value, m.value) == (n.value & (m.value ^ -1)));
     3527        }
     3528    }
     3529}
     3530
     3531void testBIC64()
     3532{
     3533    if (JSC::Options::defaultB3OptLevel() < 2)
     3534        return;
     3535
     3536    // Test Pattern: d = n & (-m - 1)
     3537    auto test1 = [&] (int64_t n, int64_t m) -> int64_t {
     3538        Procedure proc;
     3539        BasicBlock* root = proc.addBlock();
     3540
     3541        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3542        Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3543        Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 1);
     3544
     3545        Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue);
     3546        Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1);
     3547        root->appendNewControlValue(
     3548            proc, Return, Origin(),
     3549            root->appendNew<Value>(proc, BitAnd, Origin(), nValue, subValue));
     3550
     3551        auto code = compileProc(proc);
     3552        if (isARM64())
     3553            checkUsesInstruction(*code, "bic");
     3554        return invoke<int64_t>(*code, n, m);
     3555    };
     3556
     3557    // Test Pattern: d = n & (m ^ -1)
     3558    auto test2 = [&] (int64_t n, int64_t m) -> int64_t {
     3559        Procedure proc;
     3560        BasicBlock* root = proc.addBlock();
     3561
     3562        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3563        Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3564        Value* minusOneValue = root->appendNew<Const64Value>(proc, Origin(), -1);
     3565
     3566        Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue);
     3567        root->appendNewControlValue(
     3568            proc, Return, Origin(),
     3569            root->appendNew<Value>(proc, BitAnd, Origin(), nValue, xorValue));
     3570
     3571        auto code = compileProc(proc);
     3572        if (isARM64())
     3573            checkUsesInstruction(*code, "bic");
     3574        return invoke<int64_t>(*code, n, m);
     3575    };
     3576
     3577    for (auto n : int64Operands()) {
     3578        for (auto m : int64Operands()) {
     3579            CHECK(test1(n.value, m.value) == (n.value & (-m.value - 1LL)));
     3580            CHECK(test2(n.value, m.value) == (n.value & (m.value ^ -1LL)));
     3581        }
     3582    }
     3583}
     3584
     3585void testOrNot32()
     3586{
     3587    if (JSC::Options::defaultB3OptLevel() < 2)
     3588        return;
     3589
     3590    // Test Pattern: d = n | (-m - 1)
     3591    auto test1 = [&] (int32_t n, int32_t m) -> int32_t {
     3592        Procedure proc;
     3593        BasicBlock* root = proc.addBlock();
     3594
     3595        Value* nValue = root->appendNew<Value>(
     3596            proc, Trunc, Origin(),
     3597            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3598        Value* mValue = root->appendNew<Value>(
     3599            proc, Trunc, Origin(),
     3600            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     3601        Value* const1 = root->appendNew<Const32Value>(proc, Origin(), 1);
     3602
     3603        Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue);
     3604        Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1);
     3605        root->appendNewControlValue(
     3606            proc, Return, Origin(),
     3607            root->appendNew<Value>(proc, BitOr, Origin(), nValue, subValue));
     3608
     3609        auto code = compileProc(proc);
     3610
     3611        if (isARM64())
     3612            checkUsesInstruction(*code, "orn");
     3613        return invoke<int32_t>(*code, n, m);
     3614    };
     3615
     3616    // Test Pattern: d = n | (m ^ -1)
     3617    auto test2 = [&] (int32_t n, int32_t m) -> int32_t {
     3618        Procedure proc;
     3619        BasicBlock* root = proc.addBlock();
     3620
     3621        Value* nValue = root->appendNew<Value>(
     3622            proc, Trunc, Origin(),
     3623            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     3624        Value* mValue = root->appendNew<Value>(
     3625            proc, Trunc, Origin(),
     3626            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     3627        Value* minusOneValue = root->appendNew<Const32Value>(proc, Origin(), -1);
     3628
     3629        Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue);
     3630        root->appendNewControlValue(
     3631            proc, Return, Origin(),
     3632            root->appendNew<Value>(proc, BitOr, Origin(), nValue, xorValue));
     3633
     3634        auto code = compileProc(proc);
     3635        if (isARM64())
     3636            checkUsesInstruction(*code, "orn");
     3637        return invoke<int32_t>(*code, n, m);
     3638    };
     3639
     3640    for (auto n : int32Operands()) {
     3641        for (auto m : int32Operands()) {
     3642            CHECK(test1(n.value, m.value) == (n.value | (-m.value - 1)));
     3643            CHECK(test2(n.value, m.value) == (n.value | (m.value ^ -1)));
     3644        }
     3645    }
     3646}
     3647
     3648void testOrNot64()
     3649{
     3650    if (JSC::Options::defaultB3OptLevel() < 2)
     3651        return;
     3652
     3653    // Test Pattern: d = n | (-m - 1)
     3654    auto test1 = [&] (int64_t n, int64_t m) -> int64_t {
     3655        Procedure proc;
     3656        BasicBlock* root = proc.addBlock();
     3657
     3658        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3659        Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3660        Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 1);
     3661
     3662        Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue);
     3663        Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1);
     3664        root->appendNewControlValue(
     3665            proc, Return, Origin(),
     3666            root->appendNew<Value>(proc, BitOr, Origin(), nValue, subValue));
     3667
     3668        auto code = compileProc(proc);
     3669        if (isARM64())
     3670            checkUsesInstruction(*code, "orn");
     3671        return invoke<int64_t>(*code, n, m);
     3672    };
     3673
     3674    // Test Pattern: d = n | (m ^ -1)
     3675    auto test2 = [&] (int64_t n, int64_t m) -> int64_t {
     3676        Procedure proc;
     3677        BasicBlock* root = proc.addBlock();
     3678
     3679        Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     3680        Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     3681        Value* minusOneValue = root->appendNew<Const64Value>(proc, Origin(), -1);
     3682
     3683        Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue);
     3684        root->appendNewControlValue(
     3685            proc, Return, Origin(),
     3686            root->appendNew<Value>(proc, BitOr, Origin(), nValue, xorValue));
     3687
     3688        auto code = compileProc(proc);
     3689        if (isARM64())
     3690            checkUsesInstruction(*code, "orn");
     3691        return invoke<int64_t>(*code, n, m);
     3692    };
     3693
     3694    for (auto n : int64Operands()) {
     3695        for (auto m : int64Operands()) {
     3696            CHECK(test1(n.value, m.value) == (n.value | (-m.value - 1LL)));
     3697            CHECK(test2(n.value, m.value) == (n.value | (m.value ^ -1LL)));
     3698        }
    33063699    }
    33073700}
    … …  
    41994592    RUN(testUbfiz64ShiftAnd());
    42004593    RUN(testUbfiz64AndShift());
    4201     RUN(testBitFieldInsert32());
    4202     RUN(testBitFieldInsert64());
     4594    RUN(testInsertBitField32());
     4595    RUN(testInsertBitField64());
     4596    RUN(testExtractInsertBitfieldAtLowEnd32());
     4597    RUN(testExtractInsertBitfieldAtLowEnd64());
     4598    RUN(testBIC32());
     4599    RUN(testBIC64());
     4600    RUN(testOrNot32());
     4601    RUN(testOrNot64());
    42034602    RUN(testBitAndZeroShiftRightArgImmMask32());
    42044603    RUN(testBitAndZeroShiftRightArgImmMask64());
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r279253 r279362  
    1675516755            merge->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
    1675616756                jit.move(params[2].gpr(), params[0].gpr());
    16757                 jit.bitFieldInsert64(params[1].gpr(), CCallHelpers::TrustedImm32(0), CCallHelpers::TrustedImm32(64 - MacroAssembler::maxNumberOfAllowedPACBits), params[0].gpr());
     16757                jit.insertBitField64(params[1].gpr(), CCallHelpers::TrustedImm32(0), CCallHelpers::TrustedImm32(64 - MacroAssembler::maxNumberOfAllowedPACBits), params[0].gpr());
    1675816758            });
    1675916759
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp

    r279256 r279362  
    11121112#if CPU(ARM64E)
    11131113    if (kind == Gigacage::Primitive)
    1114         bitFieldInsert64(storage, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), tempReg);
     1114        insertBitField64(storage, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), tempReg);
    11151115    if (skip.isSet())
    11161116        skip.link(this);
    … …  
    11491149            andPtr(TrustedImmPtr(Gigacage::mask(kind)), tempReg);
    11501150            addPtr(scratch, tempReg);
    1151             bitFieldInsert64(tempReg, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), storage);
     1151            insertBitField64(tempReg, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), storage);
    11521152#else
    11531153            andPtr(TrustedImmPtr(Gigacage::mask(kind)), storage);
Note: See TracChangeset for help on using the changeset viewer.