AlignmentMaskAnalysis.cpp (3231B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jit/AlignmentMaskAnalysis.h" 8 #include "jit/MIR-wasm.h" 9 #include "jit/MIR.h" 10 #include "jit/MIRGraph.h" 11 12 using namespace js; 13 using namespace jit; 14 15 static bool IsAlignmentMask(uint32_t m) { 16 // Test whether m is just leading ones and trailing zeros. 17 return (-m & ~m) == 0; 18 } 19 20 static void AnalyzeAsmHeapAddress(MDefinition* ptr, MIRGraph& graph) { 21 // Fold (a+i)&m to (a&m)+i, provided that this doesn't change the result, 22 // since the users of the BitAnd include heap accesses. This will expose 23 // the redundancy for GVN when expressions like this: 24 // a&m 25 // (a+1)&m, 26 // (a+2)&m, 27 // are transformed into this: 28 // a&m 29 // (a&m)+1 30 // (a&m)+2 31 // and it will allow the constants to be folded by the 32 // EffectiveAddressAnalysis pass. 33 // 34 // Putting the add on the outside might seem like it exposes other users of 35 // the expression to the possibility of i32 overflow, if we aren't in wasm 36 // and they aren't naturally truncating. However, since we use MAdd::New 37 // with MIRType::Int32, we make sure that the value is truncated, just as it 38 // would be by the MBitAnd. 39 40 MOZ_ASSERT(IsCompilingWasm()); 41 42 if (!ptr->isBitAnd()) { 43 return; 44 } 45 46 MDefinition* lhs = ptr->toBitAnd()->getOperand(0); 47 MDefinition* rhs = ptr->toBitAnd()->getOperand(1); 48 if (lhs->isConstant()) { 49 std::swap(lhs, rhs); 50 } 51 if (!lhs->isAdd() || !rhs->isConstant()) { 52 return; 53 } 54 55 MDefinition* op0 = lhs->toAdd()->getOperand(0); 56 MDefinition* op1 = lhs->toAdd()->getOperand(1); 57 if (op0->isConstant()) { 58 std::swap(op0, op1); 59 } 60 if (!op1->isConstant()) { 61 return; 62 } 63 64 uint32_t i = op1->toConstant()->toInt32(); 65 uint32_t m = rhs->toConstant()->toInt32(); 66 if (!IsAlignmentMask(m) || (i & m) != i) { 67 return; 68 } 69 70 // The pattern was matched! Produce the replacement expression. 71 MInstruction* and_ = MBitAnd::New(graph.alloc(), op0, rhs, MIRType::Int32); 72 ptr->block()->insertBefore(ptr->toBitAnd(), and_); 73 auto* add = MAdd::New(graph.alloc(), and_, op1, TruncateKind::Truncate); 74 ptr->block()->insertBefore(ptr->toBitAnd(), add); 75 ptr->replaceAllUsesWith(add); 76 ptr->block()->discard(ptr->toBitAnd()); 77 } 78 79 bool AlignmentMaskAnalysis::analyze() { 80 for (ReversePostorderIterator block(graph_.rpoBegin()); 81 block != graph_.rpoEnd(); block++) { 82 for (MInstructionIterator i = block->begin(); i != block->end(); i++) { 83 if (!graph_.alloc().ensureBallast()) { 84 return false; 85 } 86 87 // Note that we don't check for MWasmCompareExchangeHeap 88 // or MWasmAtomicBinopHeap, because the backend and the OOB 89 // mechanism don't support non-zero offsets for them yet. 90 if (i->isAsmJSLoadHeap()) { 91 AnalyzeAsmHeapAddress(i->toAsmJSLoadHeap()->base(), graph_); 92 } else if (i->isAsmJSStoreHeap()) { 93 AnalyzeAsmHeapAddress(i->toAsmJSStoreHeap()->base(), graph_); 94 } 95 } 96 } 97 return true; 98 }