Title: [281587] trunk/Source/_javascript_Core
Revision
281587
Author
[email protected]
Date
2021-08-25 14:19:31 -0700 (Wed, 25 Aug 2021)

Log Message

[ARM64] Fix pre-index address mode
https://bugs.webkit.org/show_bug.cgi?id=229175

Reviewed by Saam Barati.

This patch fixes the canonicalization phase for pre/post-increment address mode
due to the potential bugs commented on in the previous patch
https://bugs.webkit.org/show_bug.cgi?id=228538. And this patch removed the
temporary fix in https://bugs.webkit.org/show_bug.cgi?id=229211.

Previously, the pre-index address mode for Load instruction convert the pattern
to the canonical form like this:

    address = Add(base, offset)       address = Add(base, offset)
    ...                          -->  newMemory = Load(base, offset)
    ...                               ...
    memory = Load(base, offset)       memory = Identity(newMemory)

which is wrong. Assume "..." contains a store to a memory location that aliases for address:

    address = Add(base, offset)       address = Add(base, offset)
    ...                          -->  newMemory = Load(base, offset)
    ...                               ...
    Store(value1, address)            Store(value1, address)
    memory = Load(base, offset)       memory = Identity(newMemory)

The loaded value should always be value1 which is not true after the conversion.
So, moving the load above the store is semantically incorrect because it's not identical to
the behavior of the original program. In this case, maybe we should apply alias analysis to
detect the violations of reference updating.

To solve this problem, we moves the address value to just before the memory value instead of
moving memory value upward.

Convert Pre-Index Load Pattern to the Canonical Form:

    address = Add(base, offset)                    address = Nop
    ...                                            ...
    ...                                            newAddress = Add(base, offset)
    memory = Load(base, offset)            -->     memory = Load(base, offset)
    ...                                            ...
    parent = B3Opcode(address, ...)                parent = B3Opcode(newAddress, ...)

Convert Pre-Index Store Pattern to the Canonical Form:

    address = Add(base, offset)                    address = Nop
    ...                                            ...
    ...                                            newAddress = Add(base, offset)
    memory = Store(value1, base, offset)   -->     memory = Store(value1, base, offset)
    ...                                            ...
    parent = B3Opcode(address, ...)                parent = B3Opcode(newAddress, ...)

To move the address value downward, we need to make sure that no use reference of address between
the address and memory values.

* b3/B3CanonicalizePrePostIncrements.cpp:
(JSC::B3::canonicalizePrePostIncrements):
* b3/B3Generate.cpp:
(JSC::B3::generateToAir):
* b3/B3ValueKey.h:
* b3/B3ValueKeyInlines.h:
(JSC::B3::ValueKey::ValueKey):
* b3/testb3.h:
* b3/testb3_3.cpp:
(testLoadWithStorePreIndex32):
(testStorePreIndex32):
(testStorePreIndex64):
(testStorePostIndex32):
(testStorePostIndex64):
(addShrTests):
* runtime/OptionsList.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (281586 => 281587)


--- trunk/Source/_javascript_Core/ChangeLog	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-08-25 21:19:31 UTC (rev 281587)
@@ -1,3 +1,77 @@
+2021-08-25  Yijia Huang  <[email protected]>
+
+        [ARM64] Fix pre-index address mode
+        https://bugs.webkit.org/show_bug.cgi?id=229175
+
+        Reviewed by Saam Barati.
+
+        This patch fixes the canonicalization phase for pre/post-increment address mode
+        due to the potential bugs commented on in the previous patch
+        https://bugs.webkit.org/show_bug.cgi?id=228538. And this patch removed the 
+        temporary fix in https://bugs.webkit.org/show_bug.cgi?id=229211.
+
+        Previously, the pre-index address mode for Load instruction convert the pattern 
+        to the canonical form like this:
+
+            address = Add(base, offset)       address = Add(base, offset)
+            ...                          -->  newMemory = Load(base, offset)
+            ...                               ...
+            memory = Load(base, offset)       memory = Identity(newMemory)
+
+        which is wrong. Assume "..." contains a store to a memory location that aliases for address:
+
+            address = Add(base, offset)       address = Add(base, offset)
+            ...                          -->  newMemory = Load(base, offset)
+            ...                               ...
+            Store(value1, address)            Store(value1, address)
+            memory = Load(base, offset)       memory = Identity(newMemory)
+
+        The loaded value should always be value1 which is not true after the conversion.
+        So, moving the load above the store is semantically incorrect because it's not identical to
+        the behavior of the original program. In this case, maybe we should apply alias analysis to
+        detect the violations of reference updating.
+
+        To solve this problem, we moves the address value to just before the memory value instead of
+        moving memory value upward.
+
+        Convert Pre-Index Load Pattern to the Canonical Form:
+
+            address = Add(base, offset)                    address = Nop
+            ...                                            ...
+            ...                                            newAddress = Add(base, offset)
+            memory = Load(base, offset)            -->     memory = Load(base, offset)
+            ...                                            ...
+            parent = B3Opcode(address, ...)                parent = B3Opcode(newAddress, ...)
+
+        Convert Pre-Index Store Pattern to the Canonical Form:
+
+            address = Add(base, offset)                    address = Nop
+            ...                                            ...
+            ...                                            newAddress = Add(base, offset)
+            memory = Store(value1, base, offset)   -->     memory = Store(value1, base, offset)
+            ...                                            ...
+            parent = B3Opcode(address, ...)                parent = B3Opcode(newAddress, ...)
+
+        To move the address value downward, we need to make sure that no use reference of address between
+        the address and memory values.
+
+        * b3/B3CanonicalizePrePostIncrements.cpp:
+        (JSC::B3::canonicalizePrePostIncrements):
+        * b3/B3Generate.cpp:
+        (JSC::B3::generateToAir):
+        * b3/B3ValueKey.h:
+        * b3/B3ValueKeyInlines.h:
+        (JSC::B3::ValueKey::ValueKey):
+        * b3/testb3.h:
+        * b3/testb3_3.cpp:
+        (testLoadWithStorePreIndex32):
+        (testStorePreIndex32):
+        (testStorePreIndex64):
+        (testStorePostIndex32):
+        (testStorePostIndex64):
+        (addShrTests):
+        * runtime/OptionsList.h:
+
 2021-08-25  Xan Lopez  <[email protected]>
 
         [JSC] Infinite loop in for...in after r280760

Modified: trunk/Source/_javascript_Core/b3/B3CanonicalizePrePostIncrements.cpp (281586 => 281587)


--- trunk/Source/_javascript_Core/b3/B3CanonicalizePrePostIncrements.cpp	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/b3/B3CanonicalizePrePostIncrements.cpp	2021-08-25 21:19:31 UTC (rev 281587)
@@ -52,69 +52,57 @@
 
     unsigned index { 0 };
     InsertionSet insertionSet { proc };
-    BlockInsertionSet blockInsertionSet { proc };
 
     Dominators& dominators = proc.dominators();
     BackwardsDominators& backwardsDominators = proc.backwardsDominators();
 
-    IndexSet<Value*> ignoredValues;
-    HashMap<Value*, Vector<MemoryValue*>> baseToLoads;
-    HashMap<MemoryValue*, Value*> preIndexLoadCandidates;
-    HashMap<MemoryValue*, Value*> postIndexLoadCandidates;
+    IndexSet<Value*> handledValues;
+    HashMap<Value*, unsigned> memoryToIndex;
+    HashMap<Value*, Vector<Value*>> addUses;
+    HashMap<Value*, Vector<MemoryValue*>> baseToMemories;
     HashMap<ValueKey, Vector<Value*>> baseOffsetToAddresses;
+    HashMap<MemoryValue*, Vector<Value*>> preIndexCandidates;
+    HashMap<MemoryValue*, Vector<Value*>> postIndexCandidates;
+    HashMap<BasicBlock*, HashSet<MemoryValue*>> blockToPrePostIndexCandidates;
 
-    HashMap<Value*, Vector<MemoryValue*>> baseToStores;
-    HashMap<MemoryValue*, Value*> postIndexStoreCandidates;
-
-    auto tryAddPrePostIndexCandidate = [&] (Value* value) {
+    // Strength Reduction will leave the IR in the form we're matching now. 
+    // It'll take an add(x, constant) that's an address and move the offset 
+    // into the load itself, and that's why we can match this redundancy.
+    auto tryAddCandidates = [&] (Value* value) {
         switch (value->opcode()) {
-        case Load: {
-            // Pre-Index Pattern:
-            //     address = Add(base, offset)
-            //     ...
-            //     memory = Load(base, offset)
-            // Post-Index Pattern:
-            //     memory = Load(base, 0)
-            //     ...
-            //     address = Add(base, offset)
-            auto tryAddpreIndexLoadCandidates = [&] () {
-                MemoryValue* memory = value->as<MemoryValue>();
-                if (memory->type() != Int32 && memory->type() != Int64)
-                    return;
-                if (memory->offset()) {
-                    if (!Arg::isValidIncrementIndexForm(memory->offset()))
-                        return;
-                    ValueKey baseOffsetkey = ValueKey(memory->child(0), static_cast<int64_t>(memory->offset()));
-                    if (!baseOffsetToAddresses.contains(baseOffsetkey))
-                        return;
-                    for (Value* address : baseOffsetToAddresses.get(baseOffsetkey))
-                        preIndexLoadCandidates.add(memory, address);
-                } else
-                    baseToLoads.add(memory->child(0), Vector<MemoryValue*>()).iterator->value.append(memory);
-            };
-
-            tryAddpreIndexLoadCandidates();
-            break;
-        }
-
+        case Load:
         case Store: {
-            // Pre-Index Pattern:
-            //     address = Add(base, offset)
-            //     memory = Store(value, base, offset)
-            // Post-Index Pattern:
-            //     memory = Store(value, base, 0)
-            //     ...
-            //     address = Add(base, offset)
-            auto tryUpdateBaseToStores = [&] () {
-                MemoryValue* memory = value->as<MemoryValue>();
-                if (memory->child(0)->type() != Int32 && memory->child(0)->type() != Int64)
-                    return;
-                if (memory->child(0)->hasInt() || memory->offset())
-                    return;
-                baseToStores.add(memory->child(1), Vector<MemoryValue*>()).iterator->value.append(memory);
-            };
-
-            tryUpdateBaseToStores();
+            MemoryValue* memory = value->as<MemoryValue>();
+            Value* type = value->opcode() == Load ? memory : memory->child(0);
+            if (type->type() != Int32 && type->type() != Int64)
+                break;
+            if (memory->offset()) {
+                // Pre-Index Load/Store Pattern:
+                //     address = Add(base, offset)
+                //     ...
+                //     memory = MemoryValue(base, offset)
+                ValueKey baseOffsetKey = ValueKey(memory->lastChild(), memory->offset());
+                auto iter = baseOffsetToAddresses.find(baseOffsetKey);
+                if (iter == baseOffsetToAddresses.end())
+                    break;
+                for (Value* address : iter->value) {
+                    // The goal is to move the Add to this Load/Store. We only move the Add to this Memory value
+                    // if we guarantee it dominates all uses. If there are already other uses of the Add, it guarantees
+                    // this Memory value doesn't dominate those uses. This is because we're visiting the program in pre-order
+                    // traversal, so we visit this Memory value before all the things it dominates. So if the Add has other
+                    // users, we must not dominate those users. Therefore, this MemoryValue won't be a candidate.
+                    auto addUsesIter = addUses.find(address);
+                    if (addUsesIter != addUses.end() && addUsesIter->value.size() > 0)
+                        continue;
+                    // double check offsets to avoid ValueKey collisions
+                    if (memory->offset() != static_cast<Value::OffsetType>(address->child(1)->asIntPtr()))
+                        continue;
+                    preIndexCandidates.add(memory, Vector<Value*>()).iterator->value.append(address);
+                    blockToPrePostIndexCandidates.add(memory->owner, HashSet<MemoryValue*>()).iterator->value.add(memory);
+                }
+            } else
+                baseToMemories.add(memory->lastChild(), Vector<MemoryValue*>()).iterator->value.append(memory);
+            memoryToIndex.add(memory, index);
             break;
         }
 
@@ -122,27 +110,29 @@
             Value* left = value->child(0);
             Value* right = value->child(1);
 
-            auto tryAddpostIndexCandidates = [&] () {
-                if (!right->hasIntPtr() || value->type() != Int64)
-                    return;
-                intptr_t offset = right->asIntPtr();
-                Value::OffsetType smallOffset = static_cast<Value::OffsetType>(offset);
-                if (smallOffset != offset || !Arg::isValidIncrementIndexForm(smallOffset))
-                    return;
-                // so far this Add value is a valid address candidate for both prefix and postfix pattern
-                ValueKey baseOffsetkey = ValueKey(left, static_cast<int64_t>(smallOffset));
-                baseOffsetToAddresses.add(baseOffsetkey, Vector<Value*>()).iterator->value.append(value);
-                if (baseToLoads.contains(left)) {
-                    for (MemoryValue* memory : baseToLoads.get(left))
-                        postIndexLoadCandidates.add(memory, value);
-                }
-                if (baseToStores.contains(left)) {
-                    for (MemoryValue* memory : baseToStores.get(left))
-                        postIndexStoreCandidates.add(memory, value);
-                }
-            };
+            if (!right->hasIntPtr() || value->type() != Int64)
+                break;
+            intptr_t offset = right->asIntPtr();
+            Value::OffsetType smallOffset = static_cast<Value::OffsetType>(offset);
+            if (smallOffset != offset || !Arg::isValidIncrementIndexForm(smallOffset))
+                break;
 
-            tryAddpostIndexCandidates();
+            // so far this Add value is a valid address candidate for both prefix and postfix pattern
+            addUses.add(value, Vector<Value*>());
+            ValueKey baseOffsetKey = ValueKey(left, smallOffset);
+            baseOffsetToAddresses.add(baseOffsetKey, Vector<Value*>()).iterator->value.append(value);
+
+            // Post-Index Load/Store Pattern:
+            //     memory = MemoryValue(base, 0)
+            //     ...
+            //     address = Add(base, offset)
+            auto iter = baseToMemories.find(left);
+            if (iter == baseToMemories.end())
+                break;
+            for (MemoryValue* memory : iter->value) {
+                postIndexCandidates.add(memory, Vector<Value*>()).iterator->value.append(value);
+                blockToPrePostIndexCandidates.add(memory->owner, HashSet<MemoryValue*>()).iterator->value.add(memory);
+            }
             break;
         }
 
@@ -149,11 +139,17 @@
         default:
             break;
         }
+
+        for (Value* child : value->children()) {
+            auto iter = addUses.find(child);
+            if (iter != addUses.end())
+                iter->value.append(value);
+        }
     };
 
     for (BasicBlock* basicBlock : proc.blocksInPreOrder()) {
         for (index = 0; index < basicBlock->size(); ++index)
-            tryAddPrePostIndexCandidate(basicBlock->at(index));
+            tryAddCandidates(basicBlock->at(index));
     }
 
     auto controlEquivalent = [&] (Value* v1, Value* v2) -> bool {
@@ -161,68 +157,75 @@
             || (dominators.dominates(v2->owner, v1->owner) && backwardsDominators.dominates(v1->owner, v2->owner));
     };
 
-    // This search is expensive. However, due to the greedy pattern
-    // matching, no better method can be proposed at present.
-    auto valueIndexInBasicBlock = [&] (Value* value) -> unsigned {
-        unsigned index = 0;
-        BasicBlock* block = value->owner;
-        for (index = 0; index < block->size(); ++index) {
-            if (block->at(index) == value)
-                return index;
-        }
-        return index;
-    };
+    for (const auto& pair : blockToPrePostIndexCandidates) {
+        BasicBlock* basicBlock = pair.key;
+        for (MemoryValue* memory : pair.value) {
+            if (handledValues.contains(memory))
+                continue;
 
-    for (auto pair : preIndexLoadCandidates) {
-        MemoryValue* memory = pair.key;
-        Value* address = pair.value;
-        if (ignoredValues.contains(memory) || ignoredValues.contains(address) || !controlEquivalent(memory, address))
-            continue;
-        // address = Add(base, offset)       address = Add(base, offset)
-        // ...                          -->  newMemory = Load(base, offset)
-        // ...                               ...
-        // memory = Load(base, offset)       memory = Identity(newMemory)
-        unsigned insertionIndex = valueIndexInBasicBlock(address) + 1;
-        MemoryValue* newMemory = insertionSet.insert<MemoryValue>(insertionIndex, Load, memory->type(), address->origin(), memory->lastChild());
-        newMemory->setOffset(memory->offset());
-        memory->replaceWithIdentity(newMemory);
-        insertionSet.execute(address->owner);
+            // Convert Pre-Index Load/Store Pattern to the Canonical Form:
+            //     address = Add(base, offset)                    address = Nop
+            //     ...                                            ...
+            //     ...                                            newAddress = Add(base, offset)
+            //     memory = MemoryValue(base, offset)     -->     memory = MemoryValue(base, offset)
+            //     ...                                            ...
+            //     parent = B3Opcode(address, ...)                parent = B3Opcode(newAddress, ...)
+            for (Value* address : preIndexCandidates.get(memory)) {
+                if (handledValues.contains(address) || !controlEquivalent(memory, address))
+                    continue;
 
-        ignoredValues.add(memory);
-        ignoredValues.add(address);
-    }
+                auto dominatesAllAddUses = [&] () -> bool {
+                    auto iter = addUses.find(address);
+                    ASSERT(iter != addUses.end() && iter->value.size());
+                    for (Value* parent : iter->value) {
+                        if (!dominators.dominates(memory->owner, parent->owner))
+                            return false;
+                    }
+                    return true;
+                };
 
-    auto detectPostIndex = [&] (const HashMap<MemoryValue*, Value*>& candidates) {
-        for (auto pair : candidates) {
-            MemoryValue* memory = pair.key;
-            Value* address = pair.value;
-            if (ignoredValues.contains(memory) || ignoredValues.contains(address) || !controlEquivalent(memory, address))
-                continue;
+                if (!dominatesAllAddUses())
+                    continue;
 
-            unsigned insertionIndex = valueIndexInBasicBlock(memory);
-            Value* newOffset = insertionSet.insert<Const64Value>(insertionIndex, memory->origin(), address->child(1)->asInt());
-            Value* newAddress = insertionSet.insert<Value>(insertionIndex, Add, memory->origin(), address->child(0), newOffset);
-            address->replaceWithIdentity(newAddress);
-            insertionSet.execute(memory->owner);
+                unsigned insertionIndex = memoryToIndex.get(memory);
+                Value* newAddress = insertionSet.insert<Value>(insertionIndex, Add, memory->origin(), address->child(0), address->child(1));
+                for (Value* parent : addUses.get(address)) {
+                    for (unsigned i = 0; i < parent->numChildren(); ++i) {
+                        Value*& child = parent->child(i);
+                        if (child == address)
+                            child = newAddress;
+                    }
+                }
+                address->replaceWithNopIgnoringType();
 
-            ignoredValues.add(memory);
-            ignoredValues.add(address);
+                handledValues.add(memory);
+                handledValues.add(address);
+            }
+
+            // Convert Post-Index Load/Store Pattern to the Canonical Form:
+            //     ...                                  newOffset = Constant
+            //     ...                                  newAddress = Add(base, newOffset)
+            //     memory = MemoryValue(base, 0)        memory = MemoryValue(base, 0)
+            //     ...                            -->   ...
+            //     address = Add(base, offset)          address = Identity(newAddress)
+            for (Value* address : postIndexCandidates.get(memory)) {
+                if (handledValues.contains(address) || !controlEquivalent(memory, address))
+                    continue;
+
+                unsigned insertionIndex = memoryToIndex.get(memory);
+                Value* newOffset = insertionSet.insert<Const64Value>(insertionIndex, memory->origin(), address->child(1)->asInt());
+                Value* newAddress = insertionSet.insert<Value>(insertionIndex, Add, memory->origin(), address->child(0), newOffset);
+                address->replaceWithIdentity(newAddress);
+
+                handledValues.add(memory);
+                handledValues.add(address);
+            }
         }
-    };
+        // After this executes, memoryToIndex no longer contains up to date information for this block.
+        // But that's ok because we never touch this block again.
+        insertionSet.execute(basicBlock);
+    }
 
-    // ...                                  newOffset = Constant
-    // ...                                  newAddress = Add(base, newOffset)
-    // memory = Load(base, 0)               memory = Load(base, 0)
-    // ...                            -->   ...
-    // address = Add(base, offset)          address = Identity(newAddress)
-    detectPostIndex(postIndexLoadCandidates);
-
-    // ...                                  newOffset = Constant
-    // ...                                  newAddress = Add(base, newOffset)
-    // memory = Store(value, base, 0)       memory = Store(value, base, 0)
-    // ...                            -->   ...
-    // address = Add(base, offset)          address = Identity(newAddress)
-    detectPostIndex(postIndexStoreCandidates);
     return true;
 }
 

Modified: trunk/Source/_javascript_Core/b3/B3Generate.cpp (281586 => 281587)


--- trunk/Source/_javascript_Core/b3/B3Generate.cpp	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/b3/B3Generate.cpp	2021-08-25 21:19:31 UTC (rev 281587)
@@ -118,7 +118,7 @@
     lowerMacrosAfterOptimizations(procedure);
     legalizeMemoryOffsets(procedure);
     moveConstants(procedure);
-    if (Options::useB3CanonicalizePrePostIncrements() && procedure.optLevel() >= 2)
+    if (procedure.optLevel() >= 2)
         canonicalizePrePostIncrements(procedure);
     eliminateDeadCode(procedure);
 

Modified: trunk/Source/_javascript_Core/b3/B3ValueKey.h (281586 => 281587)


--- trunk/Source/_javascript_Core/b3/B3ValueKey.h	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/b3/B3ValueKey.h	2021-08-25 21:19:31 UTC (rev 281587)
@@ -56,7 +56,7 @@
     {
     }
 
-    ValueKey(Value* child, int64_t value);
+    ValueKey(Value* child, int32_t offset);
 
     ValueKey(Kind, Type, Value* child);
 

Modified: trunk/Source/_javascript_Core/b3/B3ValueKeyInlines.h (281586 => 281587)


--- trunk/Source/_javascript_Core/b3/B3ValueKeyInlines.h	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/b3/B3ValueKeyInlines.h	2021-08-25 21:19:31 UTC (rev 281587)
@@ -33,12 +33,14 @@
 
 namespace JSC { namespace B3 {
 
-inline ValueKey::ValueKey(Value* child, int64_t value)
+inline ValueKey::ValueKey(Value* child, int32_t offset)
 {
     m_kind = Oops;
     m_type = Void;
-    u.indices[0] = child->index();
-    u.value = value;
+    // The observation is that when both child->index() and offset are 0's,
+    // HashMap would not accept the ValueKey.
+    u.indices[0] = child->index() + 1;
+    u.indices[1] = offset + 1;
 }
 
 inline ValueKey::ValueKey(Kind kind, Type type, Value* child)

Modified: trunk/Source/_javascript_Core/b3/testb3.h (281586 => 281587)


--- trunk/Source/_javascript_Core/b3/testb3.h	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/b3/testb3.h	2021-08-25 21:19:31 UTC (rev 281587)
@@ -1164,6 +1164,7 @@
 bool shouldRun(const char* filter, const char* testName);
 
 void testLoadPreIndex32();
+void testLoadWithStorePreIndex32();
 void testLoadPreIndex64();
 void testLoadPostIndex32();
 void testLoadPostIndex64();

Modified: trunk/Source/_javascript_Core/b3/testb3_3.cpp (281586 => 281587)


--- trunk/Source/_javascript_Core/b3/testb3_3.cpp	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/b3/testb3_3.cpp	2021-08-25 21:19:31 UTC (rev 281587)
@@ -102,6 +102,83 @@
     CHECK_EQ(invoke<int32_t>(*code, bitwise_cast<intptr_t>(ptr)), test());
 }
 
+void testLoadWithStorePreIndex32()
+{
+    if (Options::defaultB3OptLevel() < 2)
+        return;
+
+    int32_t nums[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+    int32_t* ptr = nums;
+
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* loopTest = proc.addBlock();
+    BasicBlock* loopBody = proc.addBlock();
+    BasicBlock* done = proc.addBlock();
+
+    Variable* r = proc.addVariable(Int32);
+    Variable* p = proc.addVariable(Int64);
+
+    // ---------------------- Root_Block
+    // r1 = 0
+    // Upsilon(r1, ^r2)
+    // p1 = addr
+    // Upsilon(p1, ^p2)
+    Value* r1 = root->appendIntConstant(proc, Origin(), Int32, 0);
+    root->appendNew<VariableValue>(proc, B3::Set, Origin(), r, r1);
+    Value* p1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    root->appendNew<VariableValue>(proc, B3::Set, Origin(), p, p1);
+    root->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(loopTest));
+
+    // ---------------------- Loop_Test_Block
+    // loop:
+    // p2 = Phi()
+    // r2 = Phi()
+    // if r2 >= 10 goto done
+    Value* r2 = loopTest->appendNew<VariableValue>(proc, B3::Get, Origin(), r);
+    Value* p2 = loopTest->appendNew<VariableValue>(proc, B3::Get, Origin(), p);
+    Value* cond = loopTest->appendNew<Value>(proc, AboveEqual, Origin(), r2, loopTest->appendNew<Const32Value>(proc, Origin(), 10));
+    loopTest->appendNewControlValue(proc, Branch, Origin(), cond, FrequentedBlock(done), FrequentedBlock(loopBody));
+
+    // ---------------------- Loop_Body_Block
+    // p3 = p2 + 1
+    // Upsilon(p3, ^p2)
+    // p3' = &p3
+    // store(5, p3')
+    // r3 = r2 + load(p3)
+    // Upsilon(r3, ^r2)
+    // goto loop
+    Value* p3 = loopBody->appendNew<Value>(proc, Add, Origin(), p2, loopBody->appendNew<Const64Value>(proc, Origin(), 4));
+    loopBody->appendNew<VariableValue>(proc, B3::Set, Origin(), p, p3);
+    Value* p3Prime = loopBody->appendNew<Value>(proc, Opaque, Origin(), p3);
+    loopBody->appendNew<MemoryValue>(proc, Store, Origin(), loopBody->appendNew<Const32Value>(proc, Origin(), 5), p3Prime);
+    Value* r3 = loopBody->appendNew<Value>(proc, Add, Origin(), r2, loopBody->appendNew<MemoryValue>(proc, Load, Int32, Origin(), p3));
+    loopBody->appendNew<VariableValue>(proc, B3::Set, Origin(), r, r3);
+    loopBody->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(loopTest));
+
+    // ---------------------- Done_Block
+    // done:
+    // return r2
+    done->appendNewControlValue(proc, Return, Origin(), r2);
+
+    proc.resetReachability();
+    validate(proc);
+    fixSSA(proc);
+
+    auto code = compileProc(proc);
+
+    auto test = [&] () -> int32_t {
+        int32_t r = 0;
+        while (r < 10) {
+            *++ptr = 5;
+            r += *ptr;
+        }
+        return r;
+    };
+
+    CHECK_EQ(invoke<int32_t>(*code, bitwise_cast<intptr_t>(ptr)), test());
+}
+
 void testLoadPreIndex64()
 {
     if (Options::defaultB3OptLevel() < 2)
@@ -344,6 +421,7 @@
     auto code = compileProc(proc);
     if (isARM64())
         checkUsesInstruction(*code, "#4]!");
+
     intptr_t res = invoke<intptr_t>(*code, bitwise_cast<intptr_t>(ptr), 4);
     ptr = bitwise_cast<int32_t*>(res);
     CHECK_EQ(nums[2], *ptr);
@@ -368,6 +446,9 @@
     root->appendNewControlValue(proc, Return, Origin(), preIncrement);
 
     auto code = compileProc(proc);
+    if (isARM64())
+        checkUsesInstruction(*code, "#8]!");
+
     intptr_t res = invoke<intptr_t>(*code, bitwise_cast<intptr_t>(ptr), 4);
     ptr = bitwise_cast<int64_t*>(res);
     CHECK_EQ(nums[2], *ptr);
@@ -396,6 +477,7 @@
     auto code = compileProc(proc);
     if (isARM64())
         checkUsesInstruction(*code, "], #4");
+
     intptr_t res = invoke<intptr_t>(*code, bitwise_cast<intptr_t>(ptr), 4);
     ptr = bitwise_cast<int32_t*>(res);
     CHECK_EQ(nums[1], 4);
@@ -423,6 +505,7 @@
     auto code = compileProc(proc);
     if (isARM64())
         checkUsesInstruction(*code, "], #8");
+
     intptr_t res = invoke<intptr_t>(*code, bitwise_cast<intptr_t>(ptr), 4);
     ptr = bitwise_cast<int64_t*>(res);
     CHECK_EQ(nums[1], 4);
@@ -4097,17 +4180,15 @@
     RUN(testZShrArgImm32(0xffffffff, 1));
     RUN(testZShrArgImm32(0xffffffff, 63));
 
-    if (Options::useB3CanonicalizePrePostIncrements()) {
-        RUN(testLoadPreIndex32());
-        RUN(testLoadPreIndex64());
-        RUN(testLoadPostIndex32());
-        RUN(testLoadPostIndex64());
+    RUN(testLoadPreIndex32());
+    RUN(testLoadPreIndex64());
+    RUN(testLoadPostIndex32());
+    RUN(testLoadPostIndex64());
 
-        RUN(testStorePreIndex32());
-        RUN(testStorePreIndex64());
-        RUN(testStorePostIndex32());
-        RUN(testStorePostIndex64());
-    }
+    RUN(testStorePreIndex32());
+    RUN(testStorePreIndex64());
+    RUN(testStorePostIndex32());
+    RUN(testStorePostIndex64());
 }
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (281586 => 281587)


--- trunk/Source/_javascript_Core/runtime/OptionsList.h	2021-08-25 21:18:16 UTC (rev 281586)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h	2021-08-25 21:19:31 UTC (rev 281587)
@@ -437,7 +437,6 @@
     v(Unsigned, maxB3TailDupBlockSize, 3, Normal, nullptr) \
     v(Unsigned, maxB3TailDupBlockSuccessors, 3, Normal, nullptr) \
     v(Bool, useB3HoistLoopInvariantValues, false, Normal, nullptr) \
-    v(Bool, useB3CanonicalizePrePostIncrements, false, Normal, nullptr) \
     \
     v(Bool, useDollarVM, false, Restricted, "installs the $vm debugging tool in global objects") \
     v(OptionString, functionOverrides, nullptr, Restricted, "file with debugging overrides for function bodies") \
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to