// Copyright 2013 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_COMPILER_MACHINE_OPERATOR_H_ #define V8_COMPILER_MACHINE_OPERATOR_H_ #include "src/base/compiler-specific.h" #include "src/base/enum-set.h" #include "src/base/flags.h" #include "src/codegen/atomic-memory-order.h" #include "src/codegen/machine-type.h" #include "src/compiler/globals.h" #include "src/compiler/write-barrier-kind.h" #include "src/zone/zone.h" namespace v8 { namespace internal { namespace compiler { // Forward declarations. struct MachineOperatorGlobalCache; class Operator; // For operators that are not supported on all platforms. class OptionalOperator final { public: OptionalOperator(bool supported, const Operator* op) : supported_(supported), op_(op) {} bool IsSupported() const { return supported_; } // Gets the operator only if it is supported. const Operator* op() const { DCHECK(supported_); return op_; } // Always gets the operator, even for unsupported operators. This is useful to // use the operator as a placeholder in a graph, for instance. const Operator* placeholder() const { return op_; } private: bool supported_; const Operator* const op_; }; // A Load needs a MachineType. using LoadRepresentation = MachineType; V8_EXPORT_PRIVATE LoadRepresentation LoadRepresentationOf(Operator const*) V8_WARN_UNUSED_RESULT; // A Word(32|64)AtomicLoad needs both a LoadRepresentation and a memory // order. class AtomicLoadParameters final { public: AtomicLoadParameters(LoadRepresentation representation, AtomicMemoryOrder order) : representation_(representation), order_(order) {} LoadRepresentation representation() const { return representation_; } AtomicMemoryOrder order() const { return order_; } private: LoadRepresentation representation_; AtomicMemoryOrder order_; }; V8_EXPORT_PRIVATE bool operator==(AtomicLoadParameters, AtomicLoadParameters); bool operator!=(AtomicLoadParameters, AtomicLoadParameters); size_t hash_value(AtomicLoadParameters); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, AtomicLoadParameters); V8_EXPORT_PRIVATE AtomicLoadParameters AtomicLoadParametersOf(Operator const*) V8_WARN_UNUSED_RESULT; enum class MemoryAccessKind { kNormal, kUnaligned, kProtected, }; size_t hash_value(MemoryAccessKind); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, MemoryAccessKind); enum class LoadTransformation { kS128Load8Splat, kS128Load16Splat, kS128Load32Splat, kS128Load64Splat, kS128Load8x8S, kS128Load8x8U, kS128Load16x4S, kS128Load16x4U, kS128Load32x2S, kS128Load32x2U, kS128Load32Zero, kS128Load64Zero, }; size_t hash_value(LoadTransformation); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, LoadTransformation); struct LoadTransformParameters { MemoryAccessKind kind; LoadTransformation transformation; }; size_t hash_value(LoadTransformParameters); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, LoadTransformParameters); V8_EXPORT_PRIVATE LoadTransformParameters const& LoadTransformParametersOf( Operator const*) V8_WARN_UNUSED_RESULT; V8_EXPORT_PRIVATE bool operator==(LoadTransformParameters, LoadTransformParameters); bool operator!=(LoadTransformParameters, LoadTransformParameters); struct LoadLaneParameters { MemoryAccessKind kind; LoadRepresentation rep; uint8_t laneidx; }; V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, LoadLaneParameters); V8_EXPORT_PRIVATE LoadLaneParameters const& LoadLaneParametersOf( Operator const*) V8_WARN_UNUSED_RESULT; // A Store needs a MachineType and a WriteBarrierKind in order to emit the // correct write barrier, and needs to state whether it is storing into the // header word, so that the value can be packed, if necessary. class StoreRepresentation final { public: StoreRepresentation(MachineRepresentation representation, WriteBarrierKind write_barrier_kind) : representation_(representation), write_barrier_kind_(write_barrier_kind) {} MachineRepresentation representation() const { return representation_; } WriteBarrierKind write_barrier_kind() const { return write_barrier_kind_; } private: MachineRepresentation representation_; WriteBarrierKind write_barrier_kind_; }; V8_EXPORT_PRIVATE bool operator==(StoreRepresentation, StoreRepresentation); bool operator!=(StoreRepresentation, StoreRepresentation); size_t hash_value(StoreRepresentation); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, StoreRepresentation); V8_EXPORT_PRIVATE StoreRepresentation const& StoreRepresentationOf( Operator const*) V8_WARN_UNUSED_RESULT; // A Word(32|64)AtomicStore needs both a StoreRepresentation and a memory order. class AtomicStoreParameters final { public: AtomicStoreParameters(MachineRepresentation representation, WriteBarrierKind write_barrier_kind, AtomicMemoryOrder order) : store_representation_(representation, write_barrier_kind), order_(order) {} MachineRepresentation representation() const { return store_representation_.representation(); } WriteBarrierKind write_barrier_kind() const { return store_representation_.write_barrier_kind(); } AtomicMemoryOrder order() const { return order_; } StoreRepresentation store_representation() const { return store_representation_; } private: StoreRepresentation store_representation_; AtomicMemoryOrder order_; }; V8_EXPORT_PRIVATE bool operator==(AtomicStoreParameters, AtomicStoreParameters); bool operator!=(AtomicStoreParameters, AtomicStoreParameters); size_t hash_value(AtomicStoreParameters); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, AtomicStoreParameters); V8_EXPORT_PRIVATE AtomicStoreParameters const& AtomicStoreParametersOf( Operator const*) V8_WARN_UNUSED_RESULT; // An UnalignedStore needs a MachineType. using UnalignedStoreRepresentation = MachineRepresentation; UnalignedStoreRepresentation const& UnalignedStoreRepresentationOf( Operator const*) V8_WARN_UNUSED_RESULT; struct StoreLaneParameters { MemoryAccessKind kind; MachineRepresentation rep; uint8_t laneidx; }; V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, StoreLaneParameters); V8_EXPORT_PRIVATE StoreLaneParameters const& StoreLaneParametersOf( Operator const*) V8_WARN_UNUSED_RESULT; class StackSlotRepresentation final { public: StackSlotRepresentation(int size, int alignment) : size_(size), alignment_(alignment) {} int size() const { return size_; } int alignment() const { return alignment_; } private: int size_; int alignment_; }; V8_EXPORT_PRIVATE bool operator==(StackSlotRepresentation, StackSlotRepresentation); bool operator!=(StackSlotRepresentation, StackSlotRepresentation); size_t hash_value(StackSlotRepresentation); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, StackSlotRepresentation); V8_EXPORT_PRIVATE StackSlotRepresentation const& StackSlotRepresentationOf( Operator const* op) V8_WARN_UNUSED_RESULT; MachineType AtomicOpType(Operator const* op) V8_WARN_UNUSED_RESULT; class S128ImmediateParameter { public: explicit S128ImmediateParameter(const uint8_t immediate[16]) { std::copy(immediate, immediate + 16, immediate_.begin()); } S128ImmediateParameter() = default; const std::array& immediate() const { return immediate_; } const uint8_t* data() const { return immediate_.data(); } uint8_t operator[](int x) const { return immediate_[x]; } private: std::array immediate_; }; V8_EXPORT_PRIVATE bool operator==(S128ImmediateParameter const& lhs, S128ImmediateParameter const& rhs); bool operator!=(S128ImmediateParameter const& lhs, S128ImmediateParameter const& rhs); size_t hash_value(S128ImmediateParameter const& p); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, S128ImmediateParameter const&); V8_EXPORT_PRIVATE S128ImmediateParameter const& S128ImmediateParameterOf( Operator const* op) V8_WARN_UNUSED_RESULT; StackCheckKind StackCheckKindOf(Operator const* op) V8_WARN_UNUSED_RESULT; // ShiftKind::kShiftOutZeros means that it is guaranteed that the bits shifted // out of the left operand are all zeros. If this is not the case, undefined // behavior (i.e., incorrect optimizations) will happen. // This is mostly useful for Smi untagging. enum class ShiftKind { kNormal, kShiftOutZeros }; size_t hash_value(ShiftKind); V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, ShiftKind); ShiftKind ShiftKindOf(Operator const*) V8_WARN_UNUSED_RESULT; // TruncateKind::kSetOverflowToMin sets the result of a saturating float-to-int // conversion to INT_MIN if the conversion returns INT_MAX due to overflow. This // makes it easier to detect an overflow. This parameter is ignored on platforms // like x64 and ia32 where a range overflow does not result in INT_MAX. enum class TruncateKind { kArchitectureDefault, kSetOverflowToMin }; std::ostream& operator<<(std::ostream& os, TruncateKind kind); size_t hash_value(TruncateKind kind); // Interface for building machine-level operators. These operators are // machine-level but machine-independent and thus define a language suitable // for generating code to run on architectures such as ia32, x64, arm, etc. class V8_EXPORT_PRIVATE MachineOperatorBuilder final : public NON_EXPORTED_BASE(ZoneObject) { public: // Flags that specify which operations are available. This is useful // for operations that are unsupported by some back-ends. enum Flag : unsigned { kNoFlags = 0u, kFloat32RoundDown = 1u << 0, kFloat64RoundDown = 1u << 1, kFloat32RoundUp = 1u << 2, kFloat64RoundUp = 1u << 3, kFloat32RoundTruncate = 1u << 4, kFloat64RoundTruncate = 1u << 5, kFloat32RoundTiesEven = 1u << 6, kFloat64RoundTiesEven = 1u << 7, kFloat64RoundTiesAway = 1u << 8, kInt32DivIsSafe = 1u << 9, kUint32DivIsSafe = 1u << 10, kWord32ShiftIsSafe = 1u << 11, kWord32Ctz = 1u << 12, kWord64Ctz = 1u << 13, kWord64CtzLowerable = 1u << 14, kWord32Popcnt = 1u << 15, kWord64Popcnt = 1u << 16, kWord32ReverseBits = 1u << 17, kWord64ReverseBits = 1u << 18, kFloat32Select = 1u << 19, kFloat64Select = 1u << 20, kInt32AbsWithOverflow = 1u << 21, kInt64AbsWithOverflow = 1u << 22, kWord32Rol = 1u << 23, kWord64Rol = 1u << 24, kWord64RolLowerable = 1u << 25, kSatConversionIsSafe = 1u << 26, kWord32Select = 1u << 27, kWord64Select = 1u << 28, kAllOptionalOps = kFloat32RoundDown | kFloat64RoundDown | kFloat32RoundUp | kFloat64RoundUp | kFloat32RoundTruncate | kFloat64RoundTruncate | kFloat64RoundTiesAway | kFloat32RoundTiesEven | kFloat64RoundTiesEven | kWord32Ctz | kWord64Ctz | kWord64CtzLowerable | kWord32Popcnt | kWord64Popcnt | kWord32ReverseBits | kWord64ReverseBits | kInt32AbsWithOverflow | kInt64AbsWithOverflow | kWord32Rol | kWord64Rol | kWord64RolLowerable | kSatConversionIsSafe | kFloat32Select | kFloat64Select | kWord32Select | kWord64Select }; using Flags = base::Flags; class AlignmentRequirements { public: enum UnalignedAccessSupport { kNoSupport, kSomeSupport, kFullSupport }; bool IsUnalignedLoadSupported(MachineRepresentation rep) const { return IsUnalignedSupported(unalignedLoadUnsupportedTypes_, rep); } bool IsUnalignedStoreSupported(MachineRepresentation rep) const { return IsUnalignedSupported(unalignedStoreUnsupportedTypes_, rep); } static AlignmentRequirements FullUnalignedAccessSupport() { return AlignmentRequirements(kFullSupport); } static AlignmentRequirements NoUnalignedAccessSupport() { return AlignmentRequirements(kNoSupport); } static AlignmentRequirements SomeUnalignedAccessUnsupported( base::EnumSet unalignedLoadUnsupportedTypes, base::EnumSet unalignedStoreUnsupportedTypes) { return AlignmentRequirements(kSomeSupport, unalignedLoadUnsupportedTypes, unalignedStoreUnsupportedTypes); } private: explicit AlignmentRequirements( AlignmentRequirements::UnalignedAccessSupport unalignedAccessSupport, base::EnumSet unalignedLoadUnsupportedTypes = base::EnumSet(), base::EnumSet unalignedStoreUnsupportedTypes = base::EnumSet()) : unalignedSupport_(unalignedAccessSupport), unalignedLoadUnsupportedTypes_(unalignedLoadUnsupportedTypes), unalignedStoreUnsupportedTypes_(unalignedStoreUnsupportedTypes) {} bool IsUnalignedSupported(base::EnumSet unsupported, MachineRepresentation rep) const { // All accesses of bytes in memory are aligned. DCHECK_NE(MachineRepresentation::kWord8, rep); switch (unalignedSupport_) { case kFullSupport: return true; case kNoSupport: return false; case kSomeSupport: return !unsupported.contains(rep); } UNREACHABLE(); } const AlignmentRequirements::UnalignedAccessSupport unalignedSupport_; const base::EnumSet unalignedLoadUnsupportedTypes_; const base::EnumSet unalignedStoreUnsupportedTypes_; }; explicit MachineOperatorBuilder( Zone* zone, MachineRepresentation word = MachineType::PointerRepresentation(), Flags supportedOperators = kNoFlags, AlignmentRequirements alignmentRequirements = AlignmentRequirements::FullUnalignedAccessSupport()); MachineOperatorBuilder(const MachineOperatorBuilder&) = delete; MachineOperatorBuilder& operator=(const MachineOperatorBuilder&) = delete; const Operator* Comment(const char* msg); const Operator* AbortCSADcheck(); const Operator* DebugBreak(); const Operator* UnsafePointerAdd(); const Operator* Word32And(); const Operator* Word32Or(); const Operator* Word32Xor(); const Operator* Word32Shl(); const Operator* Word32Shr(); const Operator* Word32Sar(ShiftKind kind); const Operator* Word32Sar() { return Word32Sar(ShiftKind::kNormal); } const Operator* Word32SarShiftOutZeros() { return Word32Sar(ShiftKind::kShiftOutZeros); } const OptionalOperator Word32Rol(); const Operator* Word32Ror(); const Operator* Word32Equal(); const Operator* Word32Clz(); const OptionalOperator Word32Ctz(); const OptionalOperator Word32Popcnt(); const OptionalOperator Word64Popcnt(); const OptionalOperator Word32ReverseBits(); const OptionalOperator Word64ReverseBits(); const Operator* Word32ReverseBytes(); const Operator* Word64ReverseBytes(); const Operator* Simd128ReverseBytes(); const OptionalOperator Int32AbsWithOverflow(); const OptionalOperator Int64AbsWithOverflow(); // Return true if the target's Word32 shift implementation is directly // compatible with JavaScript's specification. Otherwise, we have to manually // generate a mask with 0x1f on the amount ahead of generating the shift. bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; } // Return true if the target's implementation of float-to-int-conversions is a // saturating conversion rounding towards 0. Otherwise, we have to manually // generate the correct value if a saturating conversion is requested. bool SatConversionIsSafe() const { return flags_ & kSatConversionIsSafe; } const Operator* Word64And(); const Operator* Word64Or(); const Operator* Word64Xor(); const Operator* Word64Shl(); const Operator* Word64Shr(); const Operator* Word64Sar(ShiftKind kind); const Operator* Word64Sar() { return Word64Sar(ShiftKind::kNormal); } const Operator* Word64SarShiftOutZeros() { return Word64Sar(ShiftKind::kShiftOutZeros); } // 64-bit rol, ror, clz and ctz operators have two versions: the non-suffixed // ones are meant to be used in 64-bit systems and have no control input. The // "Lowerable"-suffixed ones are meant to be temporary operators in 32-bit // systems and will be lowered to 32-bit operators. They have a control input // to enable the lowering. const OptionalOperator Word64Rol(); const Operator* Word64Ror(); const Operator* Word64Clz(); const OptionalOperator Word64Ctz(); const OptionalOperator Word64RolLowerable(); const Operator* Word64RorLowerable(); const Operator* Word64ClzLowerable(); const OptionalOperator Word64CtzLowerable(); const Operator* Word64Equal(); const Operator* Int32PairAdd(); const Operator* Int32PairSub(); const Operator* Int32PairMul(); const Operator* Word32PairShl(); const Operator* Word32PairShr(); const Operator* Word32PairSar(); const Operator* Int32Add(); const Operator* Int32AddWithOverflow(); const Operator* Int32Sub(); const Operator* Int32SubWithOverflow(); const Operator* Int32Mul(); const Operator* Int32MulWithOverflow(); const Operator* Int32MulHigh(); const Operator* Int32Div(); const Operator* Int32Mod(); const Operator* Int32LessThan(); const Operator* Int32LessThanOrEqual(); const Operator* Uint32Div(); const Operator* Uint32LessThan(); const Operator* Uint32LessThanOrEqual(); const Operator* Uint32Mod(); const Operator* Uint32MulHigh(); bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; } bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; } const Operator* Int64Add(); const Operator* Int64AddWithOverflow(); const Operator* Int64Sub(); const Operator* Int64SubWithOverflow(); const Operator* Int64Mul(); const Operator* Int64Div(); const Operator* Int64Mod(); const Operator* Int64LessThan(); const Operator* Int64LessThanOrEqual(); const Operator* Uint64Div(); const Operator* Uint64LessThan(); const Operator* Uint64LessThanOrEqual(); const Operator* Uint64Mod(); // This operator reinterprets the bits of a tagged pointer as a word. const Operator* BitcastTaggedToWord(); // This operator reinterprets the bits of a tagged value as a word preserving // non-pointer bits (all the bits that are not modified by GC): // 1) smi tag // 2) weak tag // 3) smi payload if the tagged value is a smi. // Note, that it's illegal to "look" at the pointer bits of non-smi values. const Operator* BitcastTaggedToWordForTagAndSmiBits(); // This operator reinterprets the bits of a tagged MaybeObject pointer as // word. const Operator* BitcastMaybeObjectToWord(); // This operator reinterprets the bits of a word as tagged pointer. const Operator* BitcastWordToTagged(); // This operator reinterprets the bits of a word as a Smi. const Operator* BitcastWordToTaggedSigned(); // JavaScript float64 to int32/uint32 truncation. const Operator* TruncateFloat64ToWord32(); // These operators change the representation of numbers while preserving the // value of the number. Narrowing operators assume the input is representable // in the target type and are *not* defined for other inputs. // Use narrowing change operators only when there is a static guarantee that // the input value is representable in the target value. // // Some operators can have the behaviour on overflow change through specifying // TruncateKind. The exact semantics are documented in the tests in // test/cctest/compiler/test-run-machops.cc . const Operator* ChangeFloat32ToFloat64(); const Operator* ChangeFloat64ToInt32(); // narrowing const Operator* ChangeFloat64ToInt64(); const Operator* ChangeFloat64ToUint32(); // narrowing const Operator* ChangeFloat64ToUint64(); const Operator* TruncateFloat64ToInt64(TruncateKind kind); const Operator* TruncateFloat64ToUint32(); const Operator* TruncateFloat32ToInt32(TruncateKind kind); const Operator* TruncateFloat32ToUint32(TruncateKind kind); const Operator* TryTruncateFloat32ToInt64(); const Operator* TryTruncateFloat64ToInt64(); const Operator* TryTruncateFloat32ToUint64(); const Operator* TryTruncateFloat64ToUint64(); const Operator* ChangeInt32ToFloat64(); const Operator* BitcastWord32ToWord64(); const Operator* ChangeInt32ToInt64(); const Operator* ChangeInt64ToFloat64(); const Operator* ChangeUint32ToFloat64(); const Operator* ChangeUint32ToUint64(); // These operators truncate or round numbers, both changing the representation // of the number and mapping multiple input values onto the same output value. const Operator* TruncateFloat64ToFloat32(); const Operator* TruncateInt64ToInt32(); const Operator* RoundFloat64ToInt32(); const Operator* RoundInt32ToFloat32(); const Operator* RoundInt64ToFloat32(); const Operator* RoundInt64ToFloat64(); const Operator* RoundUint32ToFloat32(); const Operator* RoundUint64ToFloat32(); const Operator* RoundUint64ToFloat64(); // These operators reinterpret the bits of a floating point number as an // integer and vice versa. const Operator* BitcastFloat32ToInt32(); const Operator* BitcastFloat64ToInt64(); const Operator* BitcastInt32ToFloat32(); const Operator* BitcastInt64ToFloat64(); // These operators sign-extend to Int32/Int64 const Operator* SignExtendWord8ToInt32(); const Operator* SignExtendWord16ToInt32(); const Operator* SignExtendWord8ToInt64(); const Operator* SignExtendWord16ToInt64(); const Operator* SignExtendWord32ToInt64(); // Floating point operators always operate with IEEE 754 round-to-nearest // (single-precision). const Operator* Float32Add(); const Operator* Float32Sub(); const Operator* Float32Mul(); const Operator* Float32Div(); const Operator* Float32Sqrt(); // Floating point operators always operate with IEEE 754 round-to-nearest // (double-precision). const Operator* Float64Add(); const Operator* Float64Sub(); const Operator* Float64Mul(); const Operator* Float64Div(); const Operator* Float64Mod(); const Operator* Float64Sqrt(); // Floating point comparisons complying to IEEE 754 (single-precision). const Operator* Float32Equal(); const Operator* Float32LessThan(); const Operator* Float32LessThanOrEqual(); // Floating point comparisons complying to IEEE 754 (double-precision). const Operator* Float64Equal(); const Operator* Float64LessThan(); const Operator* Float64LessThanOrEqual(); // Floating point min/max complying to EcmaScript 6 (double-precision). const Operator* Float64Max(); const Operator* Float64Min(); // Floating point min/max complying to WebAssembly (single-precision). const Operator* Float32Max(); const Operator* Float32Min(); // Floating point abs complying to IEEE 754 (single-precision). const Operator* Float32Abs(); // Floating point abs complying to IEEE 754 (double-precision). const Operator* Float64Abs(); // Floating point rounding. const OptionalOperator Float32RoundDown(); const OptionalOperator Float64RoundDown(); const OptionalOperator Float32RoundUp(); const OptionalOperator Float64RoundUp(); const OptionalOperator Float32RoundTruncate(); const OptionalOperator Float64RoundTruncate(); const OptionalOperator Float64RoundTiesAway(); const OptionalOperator Float32RoundTiesEven(); const OptionalOperator Float64RoundTiesEven(); // Conditional selects. Input 1 is the condition, Input 2 is the result value // if the condition is {true}, Input 3 is the result value if the condition is // false. const OptionalOperator Word32Select(); const OptionalOperator Word64Select(); const OptionalOperator Float32Select(); const OptionalOperator Float64Select(); // Floating point neg. const Operator* Float32Neg(); const Operator* Float64Neg(); // Floating point trigonometric functions (double-precision). const Operator* Float64Acos(); const Operator* Float64Acosh(); const Operator* Float64Asin(); const Operator* Float64Asinh(); const Operator* Float64Atan(); const Operator* Float64Atan2(); const Operator* Float64Atanh(); const Operator* Float64Cos(); const Operator* Float64Cosh(); const Operator* Float64Sin(); const Operator* Float64Sinh(); const Operator* Float64Tan(); const Operator* Float64Tanh(); // Floating point exponential functions (double-precision). const Operator* Float64Exp(); const Operator* Float64Expm1(); const Operator* Float64Pow(); // Floating point logarithm (double-precision). const Operator* Float64Log(); const Operator* Float64Log1p(); const Operator* Float64Log2(); const Operator* Float64Log10(); // Floating point cube root (double-precision). const Operator* Float64Cbrt(); // Floating point bit representation. const Operator* Float64ExtractLowWord32(); const Operator* Float64ExtractHighWord32(); const Operator* Float64InsertLowWord32(); const Operator* Float64InsertHighWord32(); // Change signalling NaN to quiet NaN. // Identity for any input that is not signalling NaN. const Operator* Float64SilenceNaN(); // SIMD operators. const Operator* F64x2Splat(); const Operator* F64x2Abs(); const Operator* F64x2Neg(); const Operator* F64x2Sqrt(); const Operator* F64x2Add(); const Operator* F64x2Sub(); const Operator* F64x2Mul(); const Operator* F64x2Div(); const Operator* F64x2ExtractLane(int32_t); const Operator* F64x2Min(); const Operator* F64x2Max(); const Operator* F64x2ReplaceLane(int32_t); const Operator* F64x2Eq(); const Operator* F64x2Ne(); const Operator* F64x2Lt(); const Operator* F64x2Le(); const Operator* F64x2Qfma(); const Operator* F64x2Qfms(); const Operator* F64x2Pmin(); const Operator* F64x2Pmax(); const Operator* F64x2Ceil(); const Operator* F64x2Floor(); const Operator* F64x2Trunc(); const Operator* F64x2NearestInt(); const Operator* F64x2ConvertLowI32x4S(); const Operator* F64x2ConvertLowI32x4U(); const Operator* F64x2PromoteLowF32x4(); const Operator* F32x4Splat(); const Operator* F32x4ExtractLane(int32_t); const Operator* F32x4ReplaceLane(int32_t); const Operator* F32x4SConvertI32x4(); const Operator* F32x4UConvertI32x4(); const Operator* F32x4Abs(); const Operator* F32x4Neg(); const Operator* F32x4Sqrt(); const Operator* F32x4RecipApprox(); const Operator* F32x4RecipSqrtApprox(); const Operator* F32x4Add(); const Operator* F32x4Sub(); const Operator* F32x4Mul(); const Operator* F32x4Div(); const Operator* F32x4Min(); const Operator* F32x4Max(); const Operator* F32x4Eq(); const Operator* F32x4Ne(); const Operator* F32x4Lt(); const Operator* F32x4Le(); const Operator* F32x4Qfma(); const Operator* F32x4Qfms(); const Operator* F32x4Pmin(); const Operator* F32x4Pmax(); const Operator* F32x4Ceil(); const Operator* F32x4Floor(); const Operator* F32x4Trunc(); const Operator* F32x4NearestInt(); const Operator* F32x4DemoteF64x2Zero(); const Operator* I64x2Splat(); const Operator* I64x2SplatI32Pair(); const Operator* I64x2ExtractLane(int32_t); const Operator* I64x2ReplaceLane(int32_t); const Operator* I64x2ReplaceLaneI32Pair(int32_t); const Operator* I64x2Abs(); const Operator* I64x2Neg(); const Operator* I64x2SConvertI32x4Low(); const Operator* I64x2SConvertI32x4High(); const Operator* I64x2UConvertI32x4Low(); const Operator* I64x2UConvertI32x4High(); const Operator* I64x2BitMask(); const Operator* I64x2Shl(); const Operator* I64x2ShrS(); const Operator* I64x2Add(); const Operator* I64x2Sub(); const Operator* I64x2Mul(); const Operator* I64x2Eq(); const Operator* I64x2Ne(); const Operator* I64x2GtS(); const Operator* I64x2GeS(); const Operator* I64x2ShrU(); const Operator* I64x2ExtMulLowI32x4S(); const Operator* I64x2ExtMulHighI32x4S(); const Operator* I64x2ExtMulLowI32x4U(); const Operator* I64x2ExtMulHighI32x4U(); const Operator* I32x4Splat(); const Operator* I32x4ExtractLane(int32_t); const Operator* I32x4ReplaceLane(int32_t); const Operator* I32x4SConvertF32x4(); const Operator* I32x4SConvertI16x8Low(); const Operator* I32x4SConvertI16x8High(); const Operator* I32x4Neg(); const Operator* I32x4Shl(); const Operator* I32x4ShrS(); const Operator* I32x4Add(); const Operator* I32x4Sub(); const Operator* I32x4Mul(); const Operator* I32x4MinS(); const Operator* I32x4MaxS(); const Operator* I32x4Eq(); const Operator* I32x4Ne(); const Operator* I32x4GtS(); const Operator* I32x4GeS(); const Operator* I32x4UConvertF32x4(); const Operator* I32x4UConvertI16x8Low(); const Operator* I32x4UConvertI16x8High(); const Operator* I32x4ShrU(); const Operator* I32x4MinU(); const Operator* I32x4MaxU(); const Operator* I32x4GtU(); const Operator* I32x4GeU(); const Operator* I32x4Abs(); const Operator* I32x4BitMask(); const Operator* I32x4DotI16x8S(); const Operator* I32x4ExtMulLowI16x8S(); const Operator* I32x4ExtMulHighI16x8S(); const Operator* I32x4ExtMulLowI16x8U(); const Operator* I32x4ExtMulHighI16x8U(); const Operator* I32x4ExtAddPairwiseI16x8S(); const Operator* I32x4ExtAddPairwiseI16x8U(); const Operator* I32x4TruncSatF64x2SZero(); const Operator* I32x4TruncSatF64x2UZero(); const Operator* I16x8Splat(); const Operator* I16x8ExtractLaneU(int32_t); const Operator* I16x8ExtractLaneS(int32_t); const Operator* I16x8ReplaceLane(int32_t); const Operator* I16x8SConvertI8x16Low(); const Operator* I16x8SConvertI8x16High(); const Operator* I16x8Neg(); const Operator* I16x8Shl(); const Operator* I16x8ShrS(); const Operator* I16x8SConvertI32x4(); const Operator* I16x8Add(); const Operator* I16x8AddSatS(); const Operator* I16x8Sub(); const Operator* I16x8SubSatS(); const Operator* I16x8Mul(); const Operator* I16x8MinS(); const Operator* I16x8MaxS(); const Operator* I16x8Eq(); const Operator* I16x8Ne(); const Operator* I16x8GtS(); const Operator* I16x8GeS(); const Operator* I16x8UConvertI8x16Low(); const Operator* I16x8UConvertI8x16High(); const Operator* I16x8ShrU(); const Operator* I16x8UConvertI32x4(); const Operator* I16x8AddSatU(); const Operator* I16x8SubSatU(); const Operator* I16x8MinU(); const Operator* I16x8MaxU(); const Operator* I16x8GtU(); const Operator* I16x8GeU(); const Operator* I16x8RoundingAverageU(); const Operator* I16x8Q15MulRSatS(); const Operator* I16x8Abs(); const Operator* I16x8BitMask(); const Operator* I16x8ExtMulLowI8x16S(); const Operator* I16x8ExtMulHighI8x16S(); const Operator* I16x8ExtMulLowI8x16U(); const Operator* I16x8ExtMulHighI8x16U(); const Operator* I16x8ExtAddPairwiseI8x16S(); const Operator* I16x8ExtAddPairwiseI8x16U(); const Operator* I8x16Splat(); const Operator* I8x16ExtractLaneU(int32_t); const Operator* I8x16ExtractLaneS(int32_t); const Operator* I8x16ReplaceLane(int32_t); const Operator* I8x16Neg(); const Operator* I8x16Shl(); const Operator* I8x16ShrS(); const Operator* I8x16SConvertI16x8(); const Operator* I8x16Add(); const Operator* I8x16AddSatS(); const Operator* I8x16Sub(); const Operator* I8x16SubSatS(); const Operator* I8x16MinS(); const Operator* I8x16MaxS(); const Operator* I8x16Eq(); const Operator* I8x16Ne(); const Operator* I8x16GtS(); const Operator* I8x16GeS(); const Operator* I8x16ShrU(); const Operator* I8x16UConvertI16x8(); const Operator* I8x16AddSatU(); const Operator* I8x16SubSatU(); const Operator* I8x16MinU(); const Operator* I8x16MaxU(); const Operator* I8x16GtU(); const Operator* I8x16GeU(); const Operator* I8x16RoundingAverageU(); const Operator* I8x16Popcnt(); const Operator* I8x16Abs(); const Operator* I8x16BitMask(); const Operator* S128Const(const uint8_t value[16]); const Operator* S128Zero(); const Operator* S128And(); const Operator* S128Or(); const Operator* S128Xor(); const Operator* S128Not(); const Operator* S128Select(); const Operator* S128AndNot(); const Operator* I8x16Swizzle(bool relaxed = false); const Operator* I8x16Shuffle(const uint8_t shuffle[16]); const Operator* V128AnyTrue(); const Operator* I64x2AllTrue(); const Operator* I32x4AllTrue(); const Operator* I16x8AllTrue(); const Operator* I8x16AllTrue(); // Relaxed SIMD operators. const Operator* I8x16RelaxedLaneSelect(); const Operator* I16x8RelaxedLaneSelect(); const Operator* I32x4RelaxedLaneSelect(); const Operator* I64x2RelaxedLaneSelect(); const Operator* F32x4RelaxedMin(); const Operator* F32x4RelaxedMax(); const Operator* F64x2RelaxedMin(); const Operator* F64x2RelaxedMax(); const Operator* I32x4RelaxedTruncF32x4S(); const Operator* I32x4RelaxedTruncF32x4U(); const Operator* I32x4RelaxedTruncF64x2SZero(); const Operator* I32x4RelaxedTruncF64x2UZero(); // load [base + index] const Operator* Load(LoadRepresentation rep); const Operator* LoadImmutable(LoadRepresentation rep); const Operator* ProtectedLoad(LoadRepresentation rep); const Operator* LoadTransform(MemoryAccessKind kind, LoadTransformation transform); // SIMD load: replace a specified lane with [base + index]. const Operator* LoadLane(MemoryAccessKind kind, LoadRepresentation rep, uint8_t laneidx); // store [base + index], value const Operator* Store(StoreRepresentation rep); const Operator* ProtectedStore(MachineRepresentation rep); // SIMD store: store a specified lane of value into [base + index]. const Operator* StoreLane(MemoryAccessKind kind, MachineRepresentation rep, uint8_t laneidx); // unaligned load [base + index] const Operator* UnalignedLoad(LoadRepresentation rep); // unaligned store [base + index], value const Operator* UnalignedStore(UnalignedStoreRepresentation rep); const Operator* StackSlot(int size, int alignment = 0); const Operator* StackSlot(MachineRepresentation rep, int alignment = 0); // Access to the machine stack. const Operator* LoadFramePointer(); const Operator* LoadParentFramePointer(); // Compares: stack_pointer [- offset] > value. The offset is optionally // applied for kFunctionEntry stack checks. const Operator* StackPointerGreaterThan(StackCheckKind kind); // Loads the offset that should be applied to the current stack // pointer before a stack check. Used as input to the // Runtime::kStackGuardWithGap call. const Operator* LoadStackCheckOffset(); // Memory barrier. const Operator* MemBarrier(); // atomic-load [base + index] const Operator* Word32AtomicLoad(AtomicLoadParameters params); // atomic-load [base + index] const Operator* Word64AtomicLoad(AtomicLoadParameters params); // atomic-store [base + index], value const Operator* Word32AtomicStore(AtomicStoreParameters params); // atomic-store [base + index], value const Operator* Word64AtomicStore(AtomicStoreParameters params); // atomic-exchange [base + index], value const Operator* Word32AtomicExchange(MachineType type); // atomic-exchange [base + index], value const Operator* Word64AtomicExchange(MachineType type); // atomic-compare-exchange [base + index], old_value, new_value const Operator* Word32AtomicCompareExchange(MachineType type); // atomic-compare-exchange [base + index], old_value, new_value const Operator* Word64AtomicCompareExchange(MachineType type); // atomic-add [base + index], value const Operator* Word32AtomicAdd(MachineType type); // atomic-sub [base + index], value const Operator* Word32AtomicSub(MachineType type); // atomic-and [base + index], value const Operator* Word32AtomicAnd(MachineType type); // atomic-or [base + index], value const Operator* Word32AtomicOr(MachineType type); // atomic-xor [base + index], value const Operator* Word32AtomicXor(MachineType type); // atomic-add [base + index], value const Operator* Word64AtomicAdd(MachineType type); // atomic-sub [base + index], value const Operator* Word64AtomicSub(MachineType type); // atomic-and [base + index], value const Operator* Word64AtomicAnd(MachineType type); // atomic-or [base + index], value const Operator* Word64AtomicOr(MachineType type); // atomic-xor [base + index], value const Operator* Word64AtomicXor(MachineType type); // atomic-pair-load [base + index] const Operator* Word32AtomicPairLoad(AtomicMemoryOrder order); // atomic-pair-sub [base + index], value_high, value-low const Operator* Word32AtomicPairStore(AtomicMemoryOrder order); // atomic-pair-add [base + index], value_high, value_low const Operator* Word32AtomicPairAdd(); // atomic-pair-sub [base + index], value_high, value-low const Operator* Word32AtomicPairSub(); // atomic-pair-and [base + index], value_high, value_low const Operator* Word32AtomicPairAnd(); // atomic-pair-or [base + index], value_high, value_low const Operator* Word32AtomicPairOr(); // atomic-pair-xor [base + index], value_high, value_low const Operator* Word32AtomicPairXor(); // atomic-pair-exchange [base + index], value_high, value_low const Operator* Word32AtomicPairExchange(); // atomic-pair-compare-exchange [base + index], old_value_high, old_value_low, // new_value_high, new_value_low const Operator* Word32AtomicPairCompareExchange(); // Target machine word-size assumed by this builder. bool Is32() const { return word() == MachineRepresentation::kWord32; } bool Is64() const { return word() == MachineRepresentation::kWord64; } MachineRepresentation word() const { return word_; } bool UnalignedLoadSupported(MachineRepresentation rep) { return alignment_requirements_.IsUnalignedLoadSupported(rep); } bool UnalignedStoreSupported(MachineRepresentation rep) { return alignment_requirements_.IsUnalignedStoreSupported(rep); } // Pseudo operators that translate to 32/64-bit operators depending on the // word-size of the target machine assumed by this builder. #define PSEUDO_OP_LIST(V) \ V(Word, And) \ V(Word, Or) \ V(Word, Xor) \ V(Word, Shl) \ V(Word, Shr) \ V(Word, Ror) \ V(Word, Clz) \ V(Word, Equal) \ V(Int, Add) \ V(Int, Sub) \ V(Int, Mul) \ V(Int, Div) \ V(Int, Mod) \ V(Int, LessThan) \ V(Int, LessThanOrEqual) \ V(Uint, Div) \ V(Uint, LessThan) \ V(Uint, Mod) #define PSEUDO_OP(Prefix, Suffix) \ const Operator* Prefix##Suffix() { \ return Is32() ? Prefix##32##Suffix() : Prefix##64##Suffix(); \ } PSEUDO_OP_LIST(PSEUDO_OP) #undef PSEUDO_OP #undef PSEUDO_OP_LIST const Operator* WordSar(ShiftKind kind = ShiftKind::kNormal) { return Is32() ? Word32Sar(kind) : Word64Sar(kind); } const Operator* WordSarShiftOutZeros() { return WordSar(ShiftKind::kShiftOutZeros); } private: Zone* zone_; MachineOperatorGlobalCache const& cache_; MachineRepresentation const word_; Flags const flags_; AlignmentRequirements const alignment_requirements_; }; DEFINE_OPERATORS_FOR_FLAGS(MachineOperatorBuilder::Flags) } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMPILER_MACHINE_OPERATOR_H_