diff --git a/src/compiler/turboshaft/assembler.h b/src/compiler/turboshaft/assembler.h index 37dfbf9ac6..3d5a9cf37e 100644 --- a/src/compiler/turboshaft/assembler.h +++ b/src/compiler/turboshaft/assembler.h @@ -367,6 +367,18 @@ class AssemblerInterface : public Superclass { WordRepresentation::Word32()) DECL_SINGLE_REP_UNARY(Word64PopCount, WordUnary, PopCount, WordRepresentation::Word64()) + DECL_MULTI_REP_UNARY(WordSignExtend8, WordUnary, WordRepresentation, + SignExtend8) + DECL_SINGLE_REP_UNARY(Word32SignExtend8, WordUnary, SignExtend8, + WordRepresentation::Word32()) + DECL_SINGLE_REP_UNARY(Word64SignExtend8, WordUnary, SignExtend8, + WordRepresentation::Word64()) + DECL_MULTI_REP_UNARY(WordSignExtend16, WordUnary, WordRepresentation, + SignExtend16) + DECL_SINGLE_REP_UNARY(Word32SignExtend16, WordUnary, SignExtend16, + WordRepresentation::Word32()) + DECL_SINGLE_REP_UNARY(Word64SignExtend16, WordUnary, SignExtend16, + WordRepresentation::Word64()) #undef DECL_SINGLE_REP_UNARY #undef DECL_MULTI_REP_UNARY diff --git a/src/compiler/turboshaft/graph-builder.cc b/src/compiler/turboshaft/graph-builder.cc index e1d84b1d87..0355ccbe90 100644 --- a/src/compiler/turboshaft/graph-builder.cc +++ b/src/compiler/turboshaft/graph-builder.cc @@ -436,6 +436,10 @@ OpIndex GraphBuilder::Process( UNARY_CASE(Word64Ctz, Word64CountTrailingZeros) UNARY_CASE(Word32Popcnt, Word32PopCount) UNARY_CASE(Word64Popcnt, Word64PopCount) + UNARY_CASE(SignExtendWord8ToInt32, Word32SignExtend8) + UNARY_CASE(SignExtendWord16ToInt32, Word32SignExtend16) + UNARY_CASE(SignExtendWord8ToInt64, Word64SignExtend8) + UNARY_CASE(SignExtendWord16ToInt64, Word64SignExtend16) UNARY_CASE(Float32Abs, Float32Abs) UNARY_CASE(Float64Abs, Float64Abs) @@ -505,6 +509,19 @@ OpIndex GraphBuilder::Process( CHANGE_CASE(ChangeFloat64ToUint32, UnsignedNarrowing, Float64, Word32) CHANGE_CASE(ChangeFloat64ToInt64, SignedNarrowing, Float64, Word64) CHANGE_CASE(ChangeFloat64ToUint64, UnsignedNarrowing, Float64, Word64) + + CHANGE_CASE(TryTruncateFloat64ToUint64, UnsignedFloatTruncateSat, Float64, + Word64) + CHANGE_CASE(TryTruncateFloat64ToUint32, UnsignedFloatTruncateSat, Float64, + Word32) + CHANGE_CASE(TryTruncateFloat32ToUint64, UnsignedFloatTruncateSat, Float32, + Word64) + CHANGE_CASE(TryTruncateFloat64ToInt64, SignedFloatTruncateSat, Float64, + Word64) + CHANGE_CASE(TryTruncateFloat64ToInt32, SignedFloatTruncateSat, Float64, + Word32) + CHANGE_CASE(TryTruncateFloat32ToInt64, SignedFloatTruncateSat, Float32, + Word64) CHANGE_CASE(Float64ExtractLowWord32, ExtractLowHalf, Float64, Word32) CHANGE_CASE(Float64ExtractHighWord32, ExtractHighHalf, Float64, Word32) #undef CHANGE_CASE @@ -541,6 +558,11 @@ OpIndex GraphBuilder::Process( RegisterRepresentation::Float64(), RegisterRepresentation::Word64()); } + case IrOpcode::kTruncateFloat64ToUint32: { + return assembler.Change( + Map(node->InputAt(0)), ChangeOp::Kind::kUnsignedFloatTruncate, + RegisterRepresentation::Float64(), RegisterRepresentation::Word32()); + } case IrOpcode::kFloat64InsertLowWord32: return assembler.Float64InsertWord32( Map(node->InputAt(0)), Map(node->InputAt(1)), diff --git a/src/compiler/turboshaft/operations.cc b/src/compiler/turboshaft/operations.cc index 5565b5009c..5bd78a4b8d 100644 --- a/src/compiler/turboshaft/operations.cc +++ b/src/compiler/turboshaft/operations.cc @@ -51,6 +51,10 @@ std::ostream& operator<<(std::ostream& os, WordUnaryOp::Kind kind) { return os << "CountTrailingZeros"; case WordUnaryOp::Kind::kPopCount: return os << "PopCount"; + case WordUnaryOp::Kind::kSignExtend8: + return os << "SignExtend8"; + case WordUnaryOp::Kind::kSignExtend16: + return os << "SignExtend16"; } } @@ -150,6 +154,8 @@ bool WordUnaryOp::IsSupported(Kind kind, WordRepresentation rep) { switch (kind) { case Kind::kCountLeadingZeros: case Kind::kReverseBytes: + case Kind::kSignExtend8: + case Kind::kSignExtend16: return true; case Kind::kCountTrailingZeros: return rep == WordRepresentation::Word32() @@ -224,6 +230,10 @@ std::ostream& operator<<(std::ostream& os, ChangeOp::Kind kind) { return os << "SignExtend"; case ChangeOp::Kind::kBitcast: return os << "Bitcast"; + case ChangeOp::Kind::kSignedFloatTruncateSat: + return os << "SignedFloatTruncateSat"; + case ChangeOp::Kind::kUnsignedFloatTruncateSat: + return os << "UnsignedFloatTruncateSat"; } } diff --git a/src/compiler/turboshaft/operations.h b/src/compiler/turboshaft/operations.h index 76a2d1600c..cd2af5698c 100644 --- a/src/compiler/turboshaft/operations.h +++ b/src/compiler/turboshaft/operations.h @@ -726,6 +726,8 @@ struct WordUnaryOp : FixedArityOperationT<1, WordUnaryOp> { kCountLeadingZeros, kCountTrailingZeros, kPopCount, + kSignExtend8, + kSignExtend16, }; Kind kind; WordRepresentation rep; @@ -898,12 +900,16 @@ struct ChangeOp : FixedArityOperationT<1, ChangeOp> { // like kSignedFloatTruncate, but overflow guaranteed to result in the // minimal integer kSignedFloatTruncateOverflowToMin, + // like kSignedFloatTruncate, but saturates to min/max value if overflow + kSignedFloatTruncateSat, // conversion to unsigned integer, rounding towards zero, // overflow behavior system-specific kUnsignedFloatTruncate, // like kUnsignedFloatTruncate, but overflow guaranteed to result in the // minimal integer kUnsignedFloatTruncateOverflowToMin, + // like kUnsignedFloatTruncate, but saturates to 0/max value if overflow + kUnsignedFloatTruncateSat, // JS semantics float64 to word32 truncation // https://tc39.es/ecma262/#sec-touint32 kJSFloatTruncate, diff --git a/src/compiler/turboshaft/recreate-schedule.cc b/src/compiler/turboshaft/recreate-schedule.cc index 54f6b56289..8d91a066d0 100644 --- a/src/compiler/turboshaft/recreate-schedule.cc +++ b/src/compiler/turboshaft/recreate-schedule.cc @@ -359,8 +359,6 @@ Node* ScheduleBuilder::ProcessOperation(const OverflowCheckedBinopOp& op) { return AddNode(o, {GetNode(op.left()), GetNode(op.right())}); } Node* ScheduleBuilder::ProcessOperation(const WordUnaryOp& op) { - DCHECK(op.rep == WordRepresentation::Word32() || - op.rep == WordRepresentation::Word64()); bool word64 = op.rep == WordRepresentation::Word64(); const Operator* o; switch (op.kind) { @@ -376,12 +374,18 @@ Node* ScheduleBuilder::ProcessOperation(const WordUnaryOp& op) { case WordUnaryOp::Kind::kPopCount: o = word64 ? machine.Word64Popcnt().op() : machine.Word32Popcnt().op(); break; + case WordUnaryOp::Kind::kSignExtend8: + o = word64 ? machine.SignExtendWord8ToInt64() + : machine.SignExtendWord8ToInt32(); + break; + case WordUnaryOp::Kind::kSignExtend16: + o = word64 ? machine.SignExtendWord16ToInt64() + : machine.SignExtendWord16ToInt32(); + break; } return AddNode(o, {GetNode(op.input())}); } Node* ScheduleBuilder::ProcessOperation(const FloatUnaryOp& op) { - DCHECK(op.rep == FloatRepresentation::Float32() || - op.rep == FloatRepresentation::Float64()); bool float64 = op.rep == FloatRepresentation::Float64(); const Operator* o; switch (op.kind) { @@ -629,6 +633,9 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { } else if (op.from == FloatRepresentation::Float64() && op.to == WordRepresentation::Word32()) { o = machine.RoundFloat64ToInt32(); + } else if (op.from == FloatRepresentation::Float32() && + op.to == WordRepresentation::Word32()) { + o = machine.TruncateFloat32ToInt32(TruncateKind::kArchitectureDefault); } else { UNIMPLEMENTED(); } @@ -637,6 +644,9 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { if (op.from == FloatRepresentation::Float64() && op.to == WordRepresentation::Word64()) { o = machine.TruncateFloat64ToInt64(TruncateKind::kSetOverflowToMin); + } else if (op.from == FloatRepresentation::Float32() && + op.to == WordRepresentation::Word32()) { + o = machine.TruncateFloat32ToInt32(TruncateKind::kSetOverflowToMin); } else { UNIMPLEMENTED(); } @@ -645,6 +655,9 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { if (op.from == FloatRepresentation::Float32() && op.to == WordRepresentation::Word32()) { o = machine.TruncateFloat32ToUint32(TruncateKind::kArchitectureDefault); + } else if (op.from == FloatRepresentation::Float64() && + op.to == WordRepresentation::Word32()) { + o = machine.TruncateFloat64ToUint32(); } else { UNIMPLEMENTED(); } @@ -776,6 +789,34 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { UNIMPLEMENTED(); } break; + case Kind::kSignedFloatTruncateSat: + if (op.from == FloatRepresentation::Float64() && + op.to == WordRepresentation::Word64()) { + o = machine.TryTruncateFloat64ToInt64(); + } else if (op.from == FloatRepresentation::Float64() && + op.to == WordRepresentation::Word32()) { + o = machine.TryTruncateFloat64ToInt32(); + } else if (op.from == FloatRepresentation::Float32() && + op.to == WordRepresentation::Word64()) { + o = machine.TryTruncateFloat32ToInt64(); + } else { + UNREACHABLE(); + } + break; + case Kind::kUnsignedFloatTruncateSat: + if (op.from == FloatRepresentation::Float64() && + op.to == WordRepresentation::Word64()) { + o = machine.TryTruncateFloat64ToUint64(); + } else if (op.from == FloatRepresentation::Float64() && + op.to == WordRepresentation::Word32()) { + o = machine.TryTruncateFloat64ToUint32(); + } else if (op.from == FloatRepresentation::Float32() && + op.to == WordRepresentation::Word64()) { + o = machine.TryTruncateFloat32ToUint64(); + } else { + UNREACHABLE(); + } + break; } return AddNode(o, {GetNode(op.input())}); }