Title: [280013] trunk/Source/_javascript_Core
Revision
280013
Author
[email protected]
Date
2021-07-16 17:53:05 -0700 (Fri, 16 Jul 2021)

Log Message

Add ExtendType to Air::Arg Index to fully utilize address computation in memory instruction for ARM64
https://bugs.webkit.org/show_bug.cgi?id=227970

Reviewed by Saam Barati.

The pattern recognition of address computation in the instructions, e.g., Load
Resistor (LDR), Store Register (STR), etc., can benefit the instruction selector.
Then, the Air operand BaseIndex containing base, index, and scale is introduced
to Air opcode. However, the <extend> option of index address is not fully leveraged
in the previous implementation.

To fill that gap, this patch adds a new member, MacroAssembler::Extend, to the current
design of BaseIndex to trigger zero/sign extension on the Index address. And this is
enabled for Store/Load with valid index address and shift amount.

Maybe, the ideal approach is to introduce a decorator (Index@EXT) to the Air operand
to provide an extension opportunity for the specific form of the Air opcode.

Load Register (LDR) calculates an address from a base register value and an
offset register value, loads a word from memory, and writes it to a register.
The offset register value can optionally be shifted and extended.

Given B3 IR:
Int @0 = ArgumentReg(%x0)
Int @1 = Z/SExt32(Trunc(ArgumentReg(%x1)))
Int @2 = scale
Int @3 = Shl(@1, @2)
Int @4 = Add(@0, @3)
Int @5 = Load(@4, ControlDependent|Reads:Top)
Void@6 = Return(@5, Terminal)

// Old optimized AIR
Move               %x1, %x1, @1
Move (%x0,%x1,2^scale), %x0, @5
Ret                %x0,      @6

// New optimized AIR
Move (%x0,%x1,2^scale), %x0, @5
Ret                %x0,      @6

Store Register (STR) calculates an address from a base register value and an
offset register value, and stores a 32-bit word or a 64-bit doubleword to the
calculated address, from a register.

Given B3 IR:
Int @0 = value
Int @1 = ArgumentReg(%x0)
Int @2 = Z/SExt32(Trunc(ArgumentReg(%x1))
Int @3 = scale
Int @4 = Shl(@2, @3)
Int @5 = Add(@1, @4)
Void@6 = Store(@0, @5, ControlDependent|Writes:Top)
Void@7 = Return(@0, Terminal)

// Old optimized AIR
Move32    %x1,               %x1, @2
Store32  %xzr, (%x0,%x1,2^scale), @6
Move       $0,               %x0, @7
Ret32     %x0,                    @7

// New optimized AIR
Store32  %xzr, (%x0,%x1,2^scale), @6
Move       $0,               %x0, @7
Ret32     %x0,                    @7

* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::BaseIndex::BaseIndex):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::indexExtendType):
(JSC::MacroAssemblerARM64::load64):
(JSC::MacroAssemblerARM64::load32):
(JSC::MacroAssemblerARM64::load16):
(JSC::MacroAssemblerARM64::load16SignedExtendTo32):
(JSC::MacroAssemblerARM64::load8):
(JSC::MacroAssemblerARM64::load8SignedExtendTo32):
(JSC::MacroAssemblerARM64::store64):
(JSC::MacroAssemblerARM64::store32):
(JSC::MacroAssemblerARM64::store16):
(JSC::MacroAssemblerARM64::store8):
(JSC::MacroAssemblerARM64::loadDouble):
(JSC::MacroAssemblerARM64::loadFloat):
(JSC::MacroAssemblerARM64::storeDouble):
(JSC::MacroAssemblerARM64::storeFloat):
* b3/B3LowerToAir.cpp:
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::index):
(JSC::B3::Air::Arg::asBaseIndex const):
* b3/testb3.h:
* b3/testb3_2.cpp:
(testLoadZeroExtendIndexAddress):
(testLoadSignExtendIndexAddress):
(testStoreZeroExtendIndexAddress):
(testStoreSignExtendIndexAddress):
(addBitTests):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (280012 => 280013)


--- trunk/Source/_javascript_Core/ChangeLog	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-07-17 00:53:05 UTC (rev 280013)
@@ -1,3 +1,100 @@
+2021-07-16  Yijia Huang  <[email protected]>
+
+        Add ExtendType to Air::Arg Index to fully utilize address computation in memory instruction for ARM64
+        https://bugs.webkit.org/show_bug.cgi?id=227970
+
+        Reviewed by Saam Barati.
+
+        The pattern recognition of address computation in the instructions, e.g., Load 
+        Resistor (LDR), Store Register (STR), etc., can benefit the instruction selector.
+        Then, the Air operand BaseIndex containing base, index, and scale is introduced 
+        to Air opcode. However, the <extend> option of index address is not fully leveraged 
+        in the previous implementation. 
+
+        To fill that gap, this patch adds a new member, MacroAssembler::Extend, to the current 
+        design of BaseIndex to trigger zero/sign extension on the Index address. And this is 
+        enabled for Store/Load with valid index address and shift amount.
+
+        Maybe, the ideal approach is to introduce a decorator (Index@EXT) to the Air operand 
+        to provide an extension opportunity for the specific form of the Air opcode.
+
+        Load Register (LDR) calculates an address from a base register value and an 
+        offset register value, loads a word from memory, and writes it to a register. 
+        The offset register value can optionally be shifted and extended.
+
+        Given B3 IR:
+        Int @0 = ArgumentReg(%x0)
+        Int @1 = Z/SExt32(Trunc(ArgumentReg(%x1)))
+        Int @2 = scale
+        Int @3 = Shl(@1, @2)
+        Int @4 = Add(@0, @3)
+        Int @5 = Load(@4, ControlDependent|Reads:Top)
+        Void@6 = Return(@5, Terminal)
+
+        // Old optimized AIR
+        Move               %x1, %x1, @1
+        Move (%x0,%x1,2^scale), %x0, @5
+        Ret                %x0,      @6
+
+        // New optimized AIR
+        Move (%x0,%x1,2^scale), %x0, @5
+        Ret                %x0,      @6
+
+        Store Register (STR) calculates an address from a base register value and an 
+        offset register value, and stores a 32-bit word or a 64-bit doubleword to the 
+        calculated address, from a register.
+
+        Given B3 IR:
+        Int @0 = value
+        Int @1 = ArgumentReg(%x0)
+        Int @2 = Z/SExt32(Trunc(ArgumentReg(%x1))
+        Int @3 = scale
+        Int @4 = Shl(@2, @3)
+        Int @5 = Add(@1, @4)
+        Void@6 = Store(@0, @5, ControlDependent|Writes:Top)
+        Void@7 = Return(@0, Terminal)
+
+        // Old optimized AIR
+        Move32    %x1,               %x1, @2
+        Store32  %xzr, (%x0,%x1,2^scale), @6
+        Move       $0,               %x0, @7
+        Ret32     %x0,                    @7
+
+        // New optimized AIR
+        Store32  %xzr, (%x0,%x1,2^scale), @6
+        Move       $0,               %x0, @7
+        Ret32     %x0,                    @7
+
+        * assembler/AbstractMacroAssembler.h:
+        (JSC::AbstractMacroAssembler::BaseIndex::BaseIndex):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::indexExtendType):
+        (JSC::MacroAssemblerARM64::load64):
+        (JSC::MacroAssemblerARM64::load32):
+        (JSC::MacroAssemblerARM64::load16):
+        (JSC::MacroAssemblerARM64::load16SignedExtendTo32):
+        (JSC::MacroAssemblerARM64::load8):
+        (JSC::MacroAssemblerARM64::load8SignedExtendTo32):
+        (JSC::MacroAssemblerARM64::store64):
+        (JSC::MacroAssemblerARM64::store32):
+        (JSC::MacroAssemblerARM64::store16):
+        (JSC::MacroAssemblerARM64::store8):
+        (JSC::MacroAssemblerARM64::loadDouble):
+        (JSC::MacroAssemblerARM64::loadFloat):
+        (JSC::MacroAssemblerARM64::storeDouble):
+        (JSC::MacroAssemblerARM64::storeFloat):
+        * b3/B3LowerToAir.cpp:
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::index):
+        (JSC::B3::Air::Arg::asBaseIndex const):
+        * b3/testb3.h:
+        * b3/testb3_2.cpp:
+        (testLoadZeroExtendIndexAddress):
+        (testLoadSignExtendIndexAddress):
+        (testStoreZeroExtendIndexAddress):
+        (testStoreSignExtendIndexAddress):
+        (addBitTests):
+
 2021-07-16  Saam Barati  <[email protected]>
 
         Grab the lock in FTL::Thunks::keyForSlowPathCallThunk

Modified: trunk/Source/_javascript_Core/assembler/AbstractMacroAssembler.h (280012 => 280013)


--- trunk/Source/_javascript_Core/assembler/AbstractMacroAssembler.h	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/assembler/AbstractMacroAssembler.h	2021-07-17 00:53:05 UTC (rev 280013)
@@ -124,7 +124,13 @@
         TimesEight,
         ScalePtr = isAddress64Bit() ? TimesEight : TimesFour,
     };
-    
+
+    enum class Extend : uint8_t {
+        ZExt32,
+        SExt32,
+        None
+    };
+
     struct BaseIndex;
     
     static RegisterID withSwappedRegister(RegisterID original, RegisterID left, RegisterID right)
@@ -210,12 +216,16 @@
     //
     // Describes a complex addressing mode.
     struct BaseIndex {
-        BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
+        BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0, Extend extend = Extend::None)
             : base(base)
             , index(index)
             , scale(scale)
             , offset(offset)
+            , extend(extend)
         {
+#if !CPU(ARM64)
+            ASSERT(extend == Extend::None);
+#endif
         }
         
         RegisterID base;
@@ -222,6 +232,7 @@
         RegisterID index;
         Scale scale;
         int32_t offset;
+        Extend extend;
         
         BaseIndex withOffset(int32_t additionalOffset)
         {

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (280012 => 280013)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-07-17 00:53:05 UTC (rev 280013)
@@ -1367,6 +1367,17 @@
     }
 
     // Memory access operations:
+    Assembler::ExtendType indexExtendType(BaseIndex address)
+    {
+        switch (address.extend) {
+        case Extend::ZExt32:
+            return Assembler::UXTW;
+        case Extend::SExt32:
+            return Assembler::SXTW;
+        case Extend::None:
+            return Assembler::UXTX;
+        }
+    }
 
     void load64(ImplicitAddress address, RegisterID dest)
     {
@@ -1380,12 +1391,12 @@
     void load64(BaseIndex address, RegisterID dest)
     {
         if (!address.offset && (!address.scale || address.scale == 3)) {
-            m_assembler.ldr<64>(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldr<64>(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
     }
 
@@ -1479,12 +1490,12 @@
     void load32(BaseIndex address, RegisterID dest)
     {
         if (!address.offset && (!address.scale || address.scale == 2)) {
-            m_assembler.ldr<32>(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldr<32>(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
     }
 
@@ -1526,12 +1537,12 @@
     void load16(BaseIndex address, RegisterID dest)
     {
         if (!address.offset && (!address.scale || address.scale == 1)) {
-            m_assembler.ldrh(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldrh(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldrh(dest, address.base, memoryTempRegister);
     }
 
@@ -1570,12 +1581,12 @@
     void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
     {
         if (!address.offset && (!address.scale || address.scale == 1)) {
-            m_assembler.ldrsh<32>(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldrsh<32>(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister);
     }
 
@@ -1601,12 +1612,12 @@
     void load8(BaseIndex address, RegisterID dest)
     {
         if (!address.offset && !address.scale) {
-            m_assembler.ldrb(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldrb(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldrb(dest, address.base, memoryTempRegister);
     }
     
@@ -1635,12 +1646,12 @@
     void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
     {
         if (!address.offset && !address.scale) {
-            m_assembler.ldrsb<32>(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldrsb<32>(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldrsb<32>(dest, address.base, memoryTempRegister);
     }
 
@@ -1674,12 +1685,12 @@
     void store64(RegisterID src, BaseIndex address)
     {
         if (!address.offset && (!address.scale || address.scale == 3)) {
-            m_assembler.str<64>(src, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.str<64>(src, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.str<64>(src, address.base, memoryTempRegister);
     }
     
@@ -1781,12 +1792,12 @@
     void store32(RegisterID src, BaseIndex address)
     {
         if (!address.offset && (!address.scale || address.scale == 2)) {
-            m_assembler.str<32>(src, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.str<32>(src, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.str<32>(src, address.base, memoryTempRegister);
     }
 
@@ -1848,12 +1859,12 @@
     void store16(RegisterID src, BaseIndex address)
     {
         if (!address.offset && (!address.scale || address.scale == 1)) {
-            m_assembler.strh(src, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.strh(src, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.strh(src, address.base, memoryTempRegister);
     }
 
@@ -1876,12 +1887,12 @@
     void store8(RegisterID src, BaseIndex address)
     {
         if (!address.offset && !address.scale) {
-            m_assembler.strb(src, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.strb(src, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.strb(src, address.base, memoryTempRegister);
     }
 
@@ -2189,12 +2200,12 @@
     void loadDouble(BaseIndex address, FPRegisterID dest)
     {
         if (!address.offset && (!address.scale || address.scale == 3)) {
-            m_assembler.ldr<64>(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldr<64>(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
     }
     
@@ -2216,12 +2227,12 @@
     void loadFloat(BaseIndex address, FPRegisterID dest)
     {
         if (!address.offset && (!address.scale || address.scale == 2)) {
-            m_assembler.ldr<32>(dest, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.ldr<32>(dest, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
     }
 
@@ -2473,12 +2484,12 @@
     void storeDouble(FPRegisterID src, BaseIndex address)
     {
         if (!address.offset && (!address.scale || address.scale == 3)) {
-            m_assembler.str<64>(src, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.str<64>(src, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.str<64>(src, address.base, memoryTempRegister);
     }
 
@@ -2494,12 +2505,12 @@
     void storeFloat(FPRegisterID src, BaseIndex address)
     {
         if (!address.offset && (!address.scale || address.scale == 2)) {
-            m_assembler.str<32>(src, address.base, address.index, Assembler::UXTX, address.scale);
+            m_assembler.str<32>(src, address.base, address.index, indexExtendType(address), address.scale);
             return;
         }
 
         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
-        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, Assembler::UXTX, address.scale);
+        m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, indexExtendType(address), address.scale);
         m_assembler.str<32>(src, address.base, memoryTempRegister);
     }
 

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (280012 => 280013)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2021-07-17 00:53:05 UTC (rev 280013)
@@ -499,7 +499,32 @@
         return true;
     }
 
+    bool isMergeableValue(Value* v, B3::Opcode b3Opcode, bool checkCanBeInternal)
+    { 
+        if (v->opcode() != b3Opcode)
+            return false;
+        if (checkCanBeInternal && !canBeInternal(v))
+            return false;
+        if (m_locked.contains(v->child(0)))
+            return false;
+        return true;
+    }
+
     template<typename Int, typename = Value::IsLegalOffset<Int>>
+    Arg indexArg(Tmp base, Value* index, unsigned scale, Int offset)
+    {
+#if CPU(ARM64)
+        // Maybe, the ideal approach is to introduce a decorator (Index@EXT) to the Air operand 
+        // to provide an extension opportunity for the specific form under the Air opcode.
+        if (isMergeableValue(index, ZExt32, false))
+            return Arg::index(base, tmp(index->child(0)), scale, offset, MacroAssembler::Extend::ZExt32);
+        if (isMergeableValue(index, SExt32, false))
+            return Arg::index(base, tmp(index->child(0)), scale, offset, MacroAssembler::Extend::SExt32);
+#endif
+        return Arg::index(base, tmp(index), scale, offset);
+    }
+
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
     std::optional<unsigned> scaleForShl(Value* shl, Int offset, std::optional<Width> width = std::nullopt)
     {
         if (shl->opcode() != Shl)
@@ -549,7 +574,7 @@
                     return Arg();
                 if (m_locked.contains(index->child(0)) || m_locked.contains(base))
                     return Arg();
-                return Arg::index(tmp(base), tmp(index->child(0)), *scale, offset);
+                return indexArg(tmp(base), index->child(0), *scale, offset);
             };
 
             if (Arg result = tryIndex(left, right))
@@ -561,7 +586,7 @@
                 || !Arg::isValidIndexForm(1, offset, width))
                 return fallback();
             
-            return Arg::index(tmp(left), tmp(right), 1, offset);
+            return indexArg(tmp(left), right, 1, offset);
         }
 
         case Shl: {
@@ -574,7 +599,7 @@
                 || !Arg::isValidIndexForm(1, offset, width))
                 return fallback();
 
-            return Arg::index(tmp(left), tmp(left), 1, offset);
+            return indexArg(tmp(left), left, 1, offset);
         }
 
         case FramePointer:
@@ -594,7 +619,7 @@
             // perhaps more importantly, it would allow us to avoid a truncating
             // move. See: https://bugs.webkit.org/show_bug.cgi?id=163465
 
-            return Arg::index(Tmp(wasmAddress->pinnedGPR()), tmp(pointer), 1, offset);
+            return indexArg(Tmp(wasmAddress->pinnedGPR()), pointer, 1, offset);
         }
 
         default:
@@ -2117,7 +2142,7 @@
             ASSERT(!m_locked.contains(shl->child(0)));
             ASSERT(!m_locked.contains(other));
             
-            append(leaOpcode, Arg::index(tmp(other), tmp(shl->child(0)), *scale, offset), tmp(m_value));
+            append(leaOpcode, indexArg(tmp(other), shl->child(0), *scale, offset), tmp(m_value));
             commitInternal(innerAdd);
             commitInternal(shl);
             return true;
@@ -2134,7 +2159,7 @@
             return false;
         ASSERT(!m_locked.contains(value->child(0)));
         ASSERT(!m_locked.contains(value->child(1)));
-        append(leaOpcode, Arg::index(tmp(value->child(0)), tmp(value->child(1)), 1, offset), tmp(m_value));
+        append(leaOpcode, indexArg(tmp(value->child(0)), value->child(1), 1, offset), tmp(m_value));
         commitInternal(innerAdd);
         return true;
     }
@@ -2490,15 +2515,6 @@
     void lower()
     {
         using namespace Air;
-
-        auto isMergeableB3Opcode = [&] (Value* v, B3::Opcode b3Opcode) -> bool { 
-            if (v->opcode() != b3Opcode || !canBeInternal(v))
-                return false;
-            if (m_locked.contains(v->child(0)))
-                return false;
-            return true;
-        };
-
         switch (m_value->opcode()) {
         case B3::Nop: {
             // Yes, we will totally see Nop's because some phases will replaceWithNop() instead of
@@ -2599,10 +2615,10 @@
                         if (airOpcode != MultiplyAdd64)
                             return Air::Oops;
                         // SMADDL: d = SExt32(n) * SExt32(m) + a
-                        if (isMergeableB3Opcode(multiplyLeft, SExt32) && isMergeableB3Opcode(multiplyRight, SExt32)) 
+                        if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
                             return MultiplyAddSignExtend32;
                         // UMADDL: d = ZExt32(n) * ZExt32(m) + a
-                        if (isMergeableB3Opcode(multiplyLeft, ZExt32) && isMergeableB3Opcode(multiplyRight, ZExt32)) 
+                        if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
                             return MultiplyAddZeroExtend32;
                         return Air::Oops;
                     };
@@ -2687,10 +2703,10 @@
                     if (airOpcode != MultiplySub64)
                         return Air::Oops;
                     // SMSUBL: d = a - SExt32(n) * SExt32(m)
-                    if (isMergeableB3Opcode(multiplyLeft, SExt32) && isMergeableB3Opcode(multiplyRight, SExt32)) 
+                    if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
                         return MultiplySubSignExtend32;
                     // UMSUBL: d = a - ZExt32(n) * ZExt32(m)
-                    if (isMergeableB3Opcode(multiplyLeft, ZExt32) && isMergeableB3Opcode(multiplyRight, ZExt32)) 
+                    if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
                         return MultiplySubZeroExtend32;
                     return Air::Oops;
                 };
@@ -2766,10 +2782,10 @@
                     if (airOpcode != MultiplyNeg64)
                         return Air::Oops;
                     // SMNEGL: d = -(SExt32(n) * SExt32(m))
-                    if (isMergeableB3Opcode(multiplyLeft, SExt32) && isMergeableB3Opcode(multiplyRight, SExt32)) 
+                    if (isMergeableValue(multiplyLeft, SExt32, true) && isMergeableValue(multiplyRight, SExt32, true)) 
                         return MultiplyNegSignExtend32;
                     // UMNEGL: d = -(ZExt32(n) * ZExt32(m))
-                    if (isMergeableB3Opcode(multiplyLeft, ZExt32) && isMergeableB3Opcode(multiplyRight, ZExt32)) 
+                    if (isMergeableValue(multiplyLeft, ZExt32, true) && isMergeableValue(multiplyRight, ZExt32, true)) 
                         return MultiplyNegZeroExtend32;
                     return Air::Oops;
                 };

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (280012 => 280013)


--- trunk/Source/_javascript_Core/b3/air/AirArg.h	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h	2021-07-17 00:53:05 UTC (rev 280013)
@@ -629,7 +629,7 @@
     }
 
     template<typename Int, typename = Value::IsLegalOffset<Int>>
-    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale, Int offset)
+    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale, Int offset, MacroAssembler::Extend extend = MacroAssembler::Extend::None)
     {
         ASSERT(base.isGP());
         ASSERT(index.isGP());
@@ -640,6 +640,7 @@
         result.m_index = index;
         result.m_scale = static_cast<int32_t>(scale);
         result.m_offset = offset;
+        result.m_extend = extend;
         return result;
     }
 
@@ -1379,7 +1380,7 @@
         ASSERT(isIndex());
         return MacroAssembler::BaseIndex(
             m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
-            static_cast<Value::OffsetType>(m_offset));
+            static_cast<Value::OffsetType>(m_offset), m_extend);
     }
 
     MacroAssembler::RelationalCondition asRelationalCondition() const
@@ -1484,6 +1485,7 @@
 private:
     int64_t m_offset { 0 };
     Kind m_kind { Invalid };
+    MacroAssembler::Extend m_extend { MacroAssembler::Extend::None };
     int32_t m_scale { 1 };
     Air::Tmp m_base;
     Air::Tmp m_index;

Modified: trunk/Source/_javascript_Core/b3/testb3.h (280012 => 280013)


--- trunk/Source/_javascript_Core/b3/testb3.h	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/b3/testb3.h	2021-07-17 00:53:05 UTC (rev 280013)
@@ -826,6 +826,10 @@
 void testArg(int argument);
 void testReturnConst64(int64_t value);
 void testReturnVoid();
+void testLoadZeroExtendIndexAddress();
+void testLoadSignExtendIndexAddress();
+void testStoreZeroExtendIndexAddress();
+void testStoreSignExtendIndexAddress();
 void testAddArg(int);
 void testAddArgs(int, int);
 void testAddArgImm(int, int);

Modified: trunk/Source/_javascript_Core/b3/testb3_2.cpp (280012 => 280013)


--- trunk/Source/_javascript_Core/b3/testb3_2.cpp	2021-07-17 00:47:54 UTC (rev 280012)
+++ trunk/Source/_javascript_Core/b3/testb3_2.cpp	2021-07-17 00:53:05 UTC (rev 280013)
@@ -297,6 +297,314 @@
     compileAndRun<void>(proc);
 }
 
+void testLoadZeroExtendIndexAddress()
+{
+    if (Options::defaultB3OptLevel() < 2)
+        return;
+
+    auto test32 = [&] (uint32_t index, int32_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* baseValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, ZExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), baseValue, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<Value>(
+            proc, Return, Origin(), 
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address));
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 2 ? ".*ldr.*uxtw#2.*" : ".*ldr.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        intptr_t addr = bitwise_cast<intptr_t>(&num);
+        intptr_t base = addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount));
+        CHECK_EQ(invoke<int32_t>(*code, base, index), num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int32Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test32(index.value, num.value, amount);
+        }
+    }
+
+    auto test64 = [&] (uint32_t index, int64_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* baseValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, ZExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), baseValue, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<Value>(
+            proc, Return, Origin(), 
+            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address));
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 3 ? ".*ldr.*uxtw#3.*" : ".*ldr.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        intptr_t addr = bitwise_cast<intptr_t>(&num);
+        intptr_t base = addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount));
+        CHECK_EQ(invoke<int64_t>(*code, base, index), num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int64Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test64(index.value, num.value, amount);
+        }
+    }
+}
+
+void testLoadSignExtendIndexAddress()
+{
+    if (Options::defaultB3OptLevel() < 2)
+        return;
+
+    auto test32 = [&] (int32_t index, int32_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* baseValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, SExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), baseValue, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<Value>(
+            proc, Return, Origin(), 
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address));
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 2 ? ".*ldr.*sxtw#2.*" : ".*ldr.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        intptr_t addr = bitwise_cast<intptr_t>(&num);
+        intptr_t base = addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount));
+        CHECK_EQ(invoke<int32_t>(*code, base, index), num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int32Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test32(index.value, num.value, amount);
+        }
+    }
+
+    auto test64 = [&] (int32_t index, int64_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* baseValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, SExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), baseValue, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<Value>(
+            proc, Return, Origin(), 
+            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address));
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 3 ? ".*ldr.*sxtw#3.*" : ".*ldr.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        intptr_t addr = bitwise_cast<intptr_t>(&num);
+        intptr_t base = addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount));
+        CHECK_EQ(invoke<int64_t>(*code, base, index), num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int64Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test64(index.value, num.value, amount);
+        }
+    }
+}
+
+void testStoreZeroExtendIndexAddress()
+{
+    if (Options::defaultB3OptLevel() < 2)
+        return;
+
+    auto test32 = [&] (uint32_t index, int32_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Const32Value>(proc, Origin(), num);
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, ZExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), base, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<MemoryValue>(proc, Store, Origin(), value, address);
+        root->appendNew<Value>(proc, Return, Origin(), value);
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 2 ? ".*str.*uxtw#2.*" : ".*str.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        int32_t slot = 12341234;
+        intptr_t addr = bitwise_cast<intptr_t>(&slot);
+        invoke<int32_t>(*code, addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount)), index);
+        CHECK_EQ(slot, num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int32Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test32(index.value, num.value, amount);
+        }
+    }
+
+    auto test64 = [&] (uint32_t index, int64_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Const64Value>(proc, Origin(), num);
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, ZExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), base, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<MemoryValue>(proc, Store, Origin(), value, address);
+        root->appendNew<Value>(proc, Return, Origin(), value);
+
+        auto code = compileProc(proc);
+        if (isARM64() && amount == 3) {
+            std::string regex(amount == 3 ? ".*str.*uxtw#3.*" : ".*str.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        int64_t slot = 12341234;
+        intptr_t addr = bitwise_cast<intptr_t>(&slot);
+        invoke<int64_t>(*code, addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount)), index);
+        CHECK_EQ(slot, num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int64Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test64(index.value, num.value, amount);
+        }
+    }
+}
+
+void testStoreSignExtendIndexAddress()
+{
+    if (Options::defaultB3OptLevel() < 2)
+        return;
+
+    auto test32 = [&] (int32_t index, int32_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Const32Value>(proc, Origin(), num);
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, SExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), base, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<MemoryValue>(proc, Store, Origin(), value, address);
+        root->appendNew<Value>(proc, Return, Origin(), value);
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 2 ? ".*str.*sxtw#2.*" : ".*str.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        int32_t slot = 12341234;
+        intptr_t addr = bitwise_cast<intptr_t>(&slot);
+        invoke<int32_t>(*code, addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount)), index);
+        CHECK_EQ(slot, num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int32Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test32(index.value, num.value, amount);
+        }
+    }
+
+    auto test64 = [&] (int32_t index, int64_t num, int32_t amount) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* value = root->appendNew<Const64Value>(proc, Origin(), num);
+        Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+        Value* index32 = root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* index64 = root->appendNew<Value>(proc, SExt32, Origin(), index32);
+        Value* scale = root->appendNew<Const32Value>(proc, Origin(), amount);
+        Value* address = root->appendNew<Value>(
+            proc, Add, Origin(), base, 
+            root->appendNew<Value>(proc, Shl, Origin(), index64, scale));
+
+        root->appendNew<MemoryValue>(proc, Store, Origin(), value, address);
+        root->appendNew<Value>(proc, Return, Origin(), value);
+
+        auto code = compileProc(proc);
+        if (isARM64()) {
+            std::string regex(amount == 3 ? ".*str.*sxtw#3.*" : ".*str.*[.*,.*].*");
+            checkUsesInstruction(*code, regex.c_str(), true);
+        }
+        int64_t slot = 12341234;
+        intptr_t addr = bitwise_cast<intptr_t>(&slot);
+        invoke<int64_t>(*code, addr - (static_cast<intptr_t>(index) << static_cast<intptr_t>(amount)), index);
+        CHECK_EQ(slot, num);
+    };
+
+    for (auto index : int32Operands()) {
+        for (auto num : int64Operands()) {
+            for (int32_t amount = 0; amount < 10; ++amount)
+                test64(index.value, num.value, amount);
+        }
+    }
+}
+
 void testAddArg(int a)
 {
     Procedure proc;
@@ -5944,6 +6252,11 @@
     RUN_BINARY(testBitXorTreeArgImm, int64Operands(), int64Operands());
     RUN_UNARY(testBitAndTreeArg32, int32Operands());
     RUN_UNARY(testBitOrTreeArg32, int32Operands());
+
+    RUN(testLoadZeroExtendIndexAddress());
+    RUN(testLoadSignExtendIndexAddress());
+    RUN(testStoreZeroExtendIndexAddress());
+    RUN(testStoreSignExtendIndexAddress());
 }
 
 #endif // ENABLE(B3_JIT)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to