diff options
Diffstat (limited to 'deps/v8/src/compiler/effect-control-linearizer.cc')
-rw-r--r-- | deps/v8/src/compiler/effect-control-linearizer.cc | 501 |
1 files changed, 161 insertions, 340 deletions
diff --git a/deps/v8/src/compiler/effect-control-linearizer.cc b/deps/v8/src/compiler/effect-control-linearizer.cc index 9a3a293055..9b12c022c4 100644 --- a/deps/v8/src/compiler/effect-control-linearizer.cc +++ b/deps/v8/src/compiler/effect-control-linearizer.cc @@ -1631,6 +1631,32 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node, return value; } +Node* EffectControlLinearizer::BuildUint32Mod(Node* lhs, Node* rhs) { + auto if_rhs_power_of_two = __ MakeLabel(); + auto done = __ MakeLabel(MachineRepresentation::kWord32); + + // Compute the mask for the {rhs}. + Node* one = __ Int32Constant(1); + Node* msk = __ Int32Sub(rhs, one); + + // Check if the {rhs} is a power of two. + __ GotoIf(__ Word32Equal(__ Word32And(rhs, msk), __ Int32Constant(0)), + &if_rhs_power_of_two); + { + // The {rhs} is not a power of two, do a generic Uint32Mod. + __ Goto(&done, __ Uint32Mod(lhs, rhs)); + } + + __ Bind(&if_rhs_power_of_two); + { + // The {rhs} is a power of two, just do a fast bit masking. + __ Goto(&done, __ Word32And(lhs, msk)); + } + + __ Bind(&done); + return done.PhiAt(0); +} + Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, Node* frame_state) { // General case for signed integer modulus, with optimization for (unknown) @@ -1639,12 +1665,19 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, // if rhs <= 0 then // rhs = -rhs // deopt if rhs == 0 + // let msk = rhs - 1 in // if lhs < 0 then - // let res = lhs % rhs in - // deopt if res == 0 - // res + // let lhs_abs = -lsh in + // let res = if rhs & msk == 0 then + // lhs_abs & msk + // else + // lhs_abs % rhs in + // if lhs < 0 then + // deopt if res == 0 + // -res + // else + // res // else - // let msk = rhs - 1 in // if rhs & msk == 0 then // lhs & msk // else @@ -1655,7 +1688,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, auto if_rhs_not_positive = __ MakeDeferredLabel(); auto if_lhs_negative = __ MakeDeferredLabel(); - auto if_power_of_two = __ MakeLabel(); + auto if_rhs_power_of_two = __ MakeLabel(); auto rhs_checked = __ MakeLabel(MachineRepresentation::kWord32); auto done = __ MakeLabel(MachineRepresentation::kWord32); @@ -1673,45 +1706,29 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, Node* vtrue0 = __ Int32Sub(zero, rhs); // Ensure that {rhs} is not zero, otherwise we'd have to return NaN. - Node* check = __ Word32Equal(vtrue0, zero); - __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), check, - frame_state); + __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), + __ Word32Equal(vtrue0, zero), frame_state); __ Goto(&rhs_checked, vtrue0); } __ Bind(&rhs_checked); rhs = rhs_checked.PhiAt(0); - // Check if {lhs} is negative. - Node* check1 = __ Int32LessThan(lhs, zero); - __ GotoIf(check1, &if_lhs_negative); - - // {lhs} non-negative. + __ GotoIf(__ Int32LessThan(lhs, zero), &if_lhs_negative); { - Node* one = __ Int32Constant(1); - Node* msk = __ Int32Sub(rhs, one); - - // Check if {rhs} minus one is a valid mask. - Node* check2 = __ Word32Equal(__ Word32And(rhs, msk), zero); - __ GotoIf(check2, &if_power_of_two); - // Compute the remainder using the generic {lhs % rhs}. - __ Goto(&done, __ Int32Mod(lhs, rhs)); - - __ Bind(&if_power_of_two); - // Compute the remainder using {lhs & msk}. - __ Goto(&done, __ Word32And(lhs, msk)); + // The {lhs} is a non-negative integer. + __ Goto(&done, BuildUint32Mod(lhs, rhs)); } __ Bind(&if_lhs_negative); { - // Compute the remainder using {lhs % msk}. - Node* vtrue1 = __ Int32Mod(lhs, rhs); + // The {lhs} is a negative integer. + Node* res = BuildUint32Mod(__ Int32Sub(zero, lhs), rhs); // Check if we would have to return -0. - Node* check = __ Word32Equal(vtrue1, zero); - __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), check, - frame_state); - __ Goto(&done, vtrue1); + __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), + __ Word32Equal(res, zero), frame_state); + __ Goto(&done, __ Int32Sub(zero, res)); } __ Bind(&done); @@ -1753,7 +1770,7 @@ Node* EffectControlLinearizer::LowerCheckedUint32Mod(Node* node, frame_state); // Perform the actual unsigned integer modulus. - return __ Uint32Mod(lhs, rhs); + return BuildUint32Mod(lhs, rhs); } Node* EffectControlLinearizer::LowerCheckedInt32Mul(Node* node, @@ -3293,16 +3310,17 @@ Node* EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state) { // If we reach this point w/o eliminating the {node} that's marked // with allow-return-hole, we cannot do anything, so just deoptimize - // in case of the hole NaN (similar to Crankshaft). + // in case of the hole NaN. + CheckFloat64HoleParameters const& params = + CheckFloat64HoleParametersOf(node->op()); Node* value = node->InputAt(0); Node* check = __ Word32Equal(__ Float64ExtractHighWord32(value), __ Int32Constant(kHoleNanUpper32)); - __ DeoptimizeIf(DeoptimizeReason::kHole, VectorSlotPair(), check, + __ DeoptimizeIf(DeoptimizeReason::kHole, params.feedback(), check, frame_state); return value; } - Node* EffectControlLinearizer::LowerCheckNotTaggedHole(Node* node, Node* frame_state) { Node* value = node->InputAt(0); @@ -3752,350 +3770,153 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { return done.PhiAt(0); } -Node* EffectControlLinearizer::LowerLoadDataViewElement(Node* node) { - ExternalArrayType element_type = ExternalArrayTypeOf(node->op()); - Node* buffer = node->InputAt(0); - Node* storage = node->InputAt(1); - Node* index = node->InputAt(2); - Node* is_little_endian = node->InputAt(3); - - // We need to keep the {buffer} alive so that the GC will not release the - // ArrayBuffer (if there's any) as long as we are still operating on it. - __ Retain(buffer); - - ElementAccess access_int8 = AccessBuilder::ForTypedArrayElement( - kExternalInt8Array, true, LoadSensitivity::kCritical); - ElementAccess access_uint8 = AccessBuilder::ForTypedArrayElement( - kExternalUint8Array, true, LoadSensitivity::kCritical); - - switch (element_type) { - case kExternalUint8Array: - return __ LoadElement(access_uint8, storage, index); - +Node* EffectControlLinearizer::BuildReverseBytes(ExternalArrayType type, + Node* value) { + switch (type) { case kExternalInt8Array: - return __ LoadElement(access_int8, storage, index); + case kExternalUint8Array: + case kExternalUint8ClampedArray: + return value; - case kExternalUint16Array: // Fall through. case kExternalInt16Array: { - auto big_endian = __ MakeLabel(); - auto done = __ MakeLabel(MachineRepresentation::kWord32); - - // If we're doing an Int16 load, sign-extend the most significant byte - // by loading it as an Int8 instead of Uint8. - ElementAccess access_msb = - element_type == kExternalInt16Array ? access_int8 : access_uint8; - - __ GotoIfNot(is_little_endian, &big_endian); - { - // Little-endian load. - Node* b0 = __ LoadElement(access_uint8, storage, index); - Node* b1 = __ LoadElement(access_msb, storage, - __ Int32Add(index, __ Int32Constant(1))); - - // result = (b1 << 8) + b0 - Node* result = __ Int32Add(__ Word32Shl(b1, __ Int32Constant(8)), b0); - __ Goto(&done, result); - } - - __ Bind(&big_endian); - { - // Big-endian load. - Node* b0 = __ LoadElement(access_msb, storage, index); - Node* b1 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(1))); - - // result = (b0 << 8) + b1; - Node* result = __ Int32Add(__ Word32Shl(b0, __ Int32Constant(8)), b1); - __ Goto(&done, result); - } - - // We're done, return {result}. - __ Bind(&done); - return done.PhiAt(0); + Node* result = __ Word32ReverseBytes(value); + result = __ Word32Sar(result, __ Int32Constant(16)); + return result; } - case kExternalUint32Array: // Fall through. - case kExternalInt32Array: // Fall through. - case kExternalFloat32Array: { - Node* b0 = __ LoadElement(access_uint8, storage, index); - Node* b1 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(1))); - Node* b2 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(2))); - Node* b3 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(3))); - - auto big_endian = __ MakeLabel(); - auto done = __ MakeLabel(MachineRepresentation::kWord32); - - __ GotoIfNot(is_little_endian, &big_endian); - { - // Little-endian load. - // result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - Node* result = - __ Word32Or(__ Word32Or(__ Word32Shl(b3, __ Int32Constant(24)), - __ Word32Shl(b2, __ Int32Constant(16))), - __ Word32Or(__ Word32Shl(b1, __ Int32Constant(8)), b0)); - __ Goto(&done, result); - } + case kExternalUint16Array: { + Node* result = __ Word32ReverseBytes(value); + result = __ Word32Shr(result, __ Int32Constant(16)); + return result; + } - __ Bind(&big_endian); - { - // Big-endian load. - // result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; - Node* result = - __ Word32Or(__ Word32Or(__ Word32Shl(b0, __ Int32Constant(24)), - __ Word32Shl(b1, __ Int32Constant(16))), - __ Word32Or(__ Word32Shl(b2, __ Int32Constant(8)), b3)); - __ Goto(&done, result); - } + case kExternalInt32Array: // Fall through. + case kExternalUint32Array: + return __ Word32ReverseBytes(value); - // We're done, return {result}. - __ Bind(&done); - if (element_type == kExternalFloat32Array) { - return __ BitcastInt32ToFloat32(done.PhiAt(0)); - } else { - return done.PhiAt(0); - } + case kExternalFloat32Array: { + Node* result = __ BitcastFloat32ToInt32(value); + result = __ Word32ReverseBytes(result); + result = __ BitcastInt32ToFloat32(result); + return result; } case kExternalFloat64Array: { - Node* b0 = __ LoadElement(access_uint8, storage, index); - Node* b1 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(1))); - Node* b2 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(2))); - Node* b3 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(3))); - Node* b4 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(4))); - Node* b5 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(5))); - Node* b6 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(6))); - Node* b7 = __ LoadElement(access_uint8, storage, - __ Int32Add(index, __ Int32Constant(7))); - - auto big_endian = __ MakeLabel(); - auto done = __ MakeLabel(MachineRepresentation::kWord32, - MachineRepresentation::kWord32); - - __ GotoIfNot(is_little_endian, &big_endian); - { - // Little-endian load. - // low_word = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - // high_word = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4; - Node* low_word = - __ Word32Or(__ Word32Or(__ Word32Shl(b3, __ Int32Constant(24)), - __ Word32Shl(b2, __ Int32Constant(16))), - __ Word32Or(__ Word32Shl(b1, __ Int32Constant(8)), b0)); - Node* high_word = - __ Word32Or(__ Word32Or(__ Word32Shl(b7, __ Int32Constant(24)), - __ Word32Shl(b6, __ Int32Constant(16))), - __ Word32Or(__ Word32Shl(b5, __ Int32Constant(8)), b4)); - __ Goto(&done, low_word, high_word); - } - - __ Bind(&big_endian); - { - // Big-endian load. - // high_word = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; - // low_word = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; - Node* high_word = - __ Word32Or(__ Word32Or(__ Word32Shl(b0, __ Int32Constant(24)), - __ Word32Shl(b1, __ Int32Constant(16))), - __ Word32Or(__ Word32Shl(b2, __ Int32Constant(8)), b3)); - Node* low_word = - __ Word32Or(__ Word32Or(__ Word32Shl(b4, __ Int32Constant(24)), - __ Word32Shl(b5, __ Int32Constant(16))), - __ Word32Or(__ Word32Shl(b6, __ Int32Constant(8)), b7)); - __ Goto(&done, low_word, high_word); + if (machine()->Is64()) { + Node* result = __ BitcastFloat64ToInt64(value); + result = __ Word64ReverseBytes(result); + result = __ BitcastInt64ToFloat64(result); + return result; + } else { + Node* lo = __ Word32ReverseBytes(__ Float64ExtractLowWord32(value)); + Node* hi = __ Word32ReverseBytes(__ Float64ExtractHighWord32(value)); + Node* result = __ Float64Constant(0.0); + result = __ Float64InsertLowWord32(result, hi); + result = __ Float64InsertHighWord32(result, lo); + return result; } - - // We're done, store the low and high words into a float64. - __ Bind(&done); - Node* result = __ Float64Constant(0.0); - result = __ Float64InsertLowWord32(result, done.PhiAt(0)); - result = __ Float64InsertHighWord32(result, done.PhiAt(1)); - return result; } - default: + case kExternalBigInt64Array: + case kExternalBigUint64Array: UNREACHABLE(); } } -void EffectControlLinearizer::LowerStoreDataViewElement(Node* node) { +Node* EffectControlLinearizer::LowerLoadDataViewElement(Node* node) { ExternalArrayType element_type = ExternalArrayTypeOf(node->op()); Node* buffer = node->InputAt(0); Node* storage = node->InputAt(1); Node* index = node->InputAt(2); - Node* value = node->InputAt(3); - Node* is_little_endian = node->InputAt(4); + Node* is_little_endian = node->InputAt(3); + + // On 64-bit platforms, we need to feed a Word64 index to the Load and + // Store operators. + if (machine()->Is64()) { + index = __ ChangeUint32ToUint64(index); + } // We need to keep the {buffer} alive so that the GC will not release the // ArrayBuffer (if there's any) as long as we are still operating on it. __ Retain(buffer); - ElementAccess access = - AccessBuilder::ForTypedArrayElement(kExternalUint8Array, true); + MachineType const machine_type = + AccessBuilder::ForTypedArrayElement(element_type, true).machine_type; - switch (element_type) { - case kExternalUint8Array: // Fall through. - case kExternalInt8Array: { - Node* b0 = __ Word32And(value, __ Int32Constant(0xFF)); - __ StoreElement(access, storage, index, b0); - break; - } - case kExternalUint16Array: // Fall through. - case kExternalInt16Array: { - Node* b0 = __ Word32And(value, __ Int32Constant(0xFF)); - Node* b1 = __ Word32And(__ Word32Shr(value, __ Int32Constant(8)), - __ Int32Constant(0xFF)); + Node* value = __ LoadUnaligned(machine_type, storage, index); + auto big_endian = __ MakeLabel(); + auto done = __ MakeLabel(machine_type.representation()); - auto big_endian = __ MakeLabel(); - auto done = __ MakeLabel(); - - __ GotoIfNot(is_little_endian, &big_endian); - { - // Little-endian store. - __ StoreElement(access, storage, index, b0); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(1)), b1); - __ Goto(&done); - } - - __ Bind(&big_endian); - { - // Big-endian store. - __ StoreElement(access, storage, index, b1); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(1)), b0); - __ Goto(&done); - } - - __ Bind(&done); - break; - } - - case kExternalUint32Array: // Fall through. - case kExternalInt32Array: // Fall through. - case kExternalFloat32Array: { - if (element_type == kExternalFloat32Array) { - value = __ BitcastFloat32ToInt32(value); - } + __ GotoIfNot(is_little_endian, &big_endian); + { // Little-endian load. +#if V8_TARGET_LITTLE_ENDIAN + __ Goto(&done, value); +#else + __ Goto(&done, BuildReverseBytes(element_type, value)); +#endif // V8_TARGET_LITTLE_ENDIAN + } - Node* b0 = __ Word32And(value, __ Int32Constant(0xFF)); - Node* b1 = __ Word32And(__ Word32Shr(value, __ Int32Constant(8)), - __ Int32Constant(0xFF)); - Node* b2 = __ Word32And(__ Word32Shr(value, __ Int32Constant(16)), - __ Int32Constant(0xFF)); - Node* b3 = __ Word32Shr(value, __ Int32Constant(24)); + __ Bind(&big_endian); + { // Big-endian load. +#if V8_TARGET_LITTLE_ENDIAN + __ Goto(&done, BuildReverseBytes(element_type, value)); +#else + __ Goto(&done, value); +#endif // V8_TARGET_LITTLE_ENDIAN + } - auto big_endian = __ MakeLabel(); - auto done = __ MakeLabel(); + // We're done, return {result}. + __ Bind(&done); + return done.PhiAt(0); +} - __ GotoIfNot(is_little_endian, &big_endian); - { - // Little-endian store. - __ StoreElement(access, storage, index, b0); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(1)), b1); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(2)), b2); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(3)), b3); - __ Goto(&done); - } +void EffectControlLinearizer::LowerStoreDataViewElement(Node* node) { + ExternalArrayType element_type = ExternalArrayTypeOf(node->op()); + Node* buffer = node->InputAt(0); + Node* storage = node->InputAt(1); + Node* index = node->InputAt(2); + Node* value = node->InputAt(3); + Node* is_little_endian = node->InputAt(4); - __ Bind(&big_endian); - { - // Big-endian store. - __ StoreElement(access, storage, index, b3); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(1)), b2); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(2)), b1); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(3)), b0); - __ Goto(&done); - } + // On 64-bit platforms, we need to feed a Word64 index to the Load and + // Store operators. + if (machine()->Is64()) { + index = __ ChangeUint32ToUint64(index); + } - __ Bind(&done); - break; - } + // We need to keep the {buffer} alive so that the GC will not release the + // ArrayBuffer (if there's any) as long as we are still operating on it. + __ Retain(buffer); - case kExternalFloat64Array: { - Node* low_word = __ Float64ExtractLowWord32(value); - Node* high_word = __ Float64ExtractHighWord32(value); - - Node* b0 = __ Word32And(low_word, __ Int32Constant(0xFF)); - Node* b1 = __ Word32And(__ Word32Shr(low_word, __ Int32Constant(8)), - __ Int32Constant(0xFF)); - Node* b2 = __ Word32And(__ Word32Shr(low_word, __ Int32Constant(16)), - __ Int32Constant(0xFF)); - Node* b3 = __ Word32Shr(low_word, __ Int32Constant(24)); - - Node* b4 = __ Word32And(high_word, __ Int32Constant(0xFF)); - Node* b5 = __ Word32And(__ Word32Shr(high_word, __ Int32Constant(8)), - __ Int32Constant(0xFF)); - Node* b6 = __ Word32And(__ Word32Shr(high_word, __ Int32Constant(16)), - __ Int32Constant(0xFF)); - Node* b7 = __ Word32Shr(high_word, __ Int32Constant(24)); - - auto big_endian = __ MakeLabel(); - auto done = __ MakeLabel(); - - __ GotoIfNot(is_little_endian, &big_endian); - { - // Little-endian store. - __ StoreElement(access, storage, index, b0); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(1)), b1); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(2)), b2); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(3)), b3); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(4)), b4); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(5)), b5); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(6)), b6); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(7)), b7); - __ Goto(&done); - } + MachineType const machine_type = + AccessBuilder::ForTypedArrayElement(element_type, true).machine_type; - __ Bind(&big_endian); - { - // Big-endian store. - __ StoreElement(access, storage, index, b7); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(1)), b6); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(2)), b5); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(3)), b4); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(4)), b3); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(5)), b2); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(6)), b1); - __ StoreElement(access, storage, - __ Int32Add(index, __ Int32Constant(7)), b0); - __ Goto(&done); - } + auto big_endian = __ MakeLabel(); + auto done = __ MakeLabel(machine_type.representation()); - __ Bind(&done); - break; - } + __ GotoIfNot(is_little_endian, &big_endian); + { // Little-endian store. +#if V8_TARGET_LITTLE_ENDIAN + __ Goto(&done, value); +#else + __ Goto(&done, BuildReverseBytes(element_type, value)); +#endif // V8_TARGET_LITTLE_ENDIAN + } - default: - UNREACHABLE(); + __ Bind(&big_endian); + { // Big-endian store. +#if V8_TARGET_LITTLE_ENDIAN + __ Goto(&done, BuildReverseBytes(element_type, value)); +#else + __ Goto(&done, value); +#endif // V8_TARGET_LITTLE_ENDIAN } + + __ Bind(&done); + __ StoreUnaligned(machine_type.representation(), storage, index, + done.PhiAt(0)); } + Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) { ExternalArrayType array_type = ExternalArrayTypeOf(node->op()); Node* buffer = node->InputAt(0); |