5#ifndef V8_COMPILER_TURBOSHAFT_INT64_LOWERING_REDUCER_H_
6#define V8_COMPILER_TURBOSHAFT_INT64_LOWERING_REDUCER_H_
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
43 if (
__ data()->wasm_module_sig()) {
78 FATAL(
"WordBinopOp kind %d not supported by int64 lowering",
79 static_cast<int>(
kind));
82 return Next::ReduceWordBinop(left, right,
kind, rep);
90 case ShiftOp::Kind::kShiftLeft:
93 case ShiftOp::Kind::kShiftRightArithmetic:
96 case ShiftOp::Kind::kShiftRightLogical:
99 case ShiftOp::Kind::kRotateRight:
102 FATAL(
"Shiftop kind %d not supported by int64 lowering",
103 static_cast<int>(
kind));
106 return Next::ReduceShift(left, right,
kind, rep);
113 return Next::ReduceComparison(left, right,
kind, rep);
123 return __ Word32Equal(
124 __ Word32BitwiseOr(
__ Word32BitwiseXor(left_low, right_low),
125 __ Word32BitwiseXor(left_high, right_high)),
128 high_comparison =
__ Int32LessThan(left_high, right_high);
129 low_comparison =
__ Uint32LessThan(left_low, right_low);
132 high_comparison =
__ Int32LessThan(left_high, right_high);
133 low_comparison =
__ Uint32LessThanOrEqual(left_low, right_low);
136 high_comparison =
__ Uint32LessThan(left_high, right_high);
137 low_comparison =
__ Uint32LessThan(left_low, right_low);
140 high_comparison =
__ Uint32LessThan(left_high, right_high);
141 low_comparison =
__ Uint32LessThanOrEqual(left_low, right_low);
145 return __ Word32BitwiseOr(
147 __ Word32BitwiseAnd(
__ Word32Equal(left_high, right_high),
154 const bool is_tail_call =
false;
155 return LowerCall(callee, frame_state, arguments, descriptor, effects,
162 const bool is_tail_call =
true;
164 return LowerCall(callee, frame_state, arguments, descriptor,
165 OpEffects().CanCallAnything(), is_tail_call);
170 uint32_t high = value.integral >> 32;
171 uint32_t low = value.integral & std::numeric_limits<uint32_t>::max();
172 return __ Tuple(
__ Word32Constant(low),
__ Word32Constant(high));
174 return Next::ReduceConstant(
kind, value);
178 const char* debug_name =
"") {
179 int32_t param_count =
static_cast<int32_t
>(
sig_->parameter_count());
181 if (parameter_index < 0) {
182 return Next::ReduceParameter(parameter_index, rep, debug_name);
184 if (parameter_index > param_count) {
187 std::count(
sig_->parameters().begin(),
sig_->parameters().end(),
189 return Next::ReduceParameter(parameter_index + param_offset, rep,
195 return __ Tuple(Next::ReduceParameter(new_index, rep),
196 Next::ReduceParameter(new_index + 1, rep));
198 return Next::ReduceParameter(new_index, rep, debug_name);
203 bool spill_caller_frame_slots) {
205 return Next::ReduceReturn(pop_count, return_values,
206 spill_caller_frame_slots);
209 for (
size_t i = 0;
i <
sig_->return_count(); ++
i) {
211 auto [low, high] =
Unpack(return_values[
i]);
218 return Next::ReduceReturn(pop_count,
base::VectorOf(lowered_values),
219 spill_caller_frame_slots);
236 __ Word32SignExtend8(
Unpack(input_pair).first));
239 __ Word32SignExtend16(
Unpack(input_pair).first));
241 auto [low, high] =
Unpack(input_pair);
242 V<Word32> reversed_low =
__ Word32ReverseBytes(low);
243 V<Word32> reversed_high =
__ Word32ReverseBytes(high);
244 return __ Tuple(reversed_high, reversed_low);
247 FATAL(
"WordUnaryOp kind %d not supported by int64 lowering",
248 static_cast<int>(
kind));
251 return Next::ReduceWordUnary(input,
kind, rep);
262 if (from != word64 && to != word64) {
263 return Next::ReduceChange(input,
kind, assumption, from, to);
266 if (from == word32 && to == word64) {
267 if (
kind == Kind::kZeroExtend) {
270 if (
kind == Kind::kSignExtend) {
274 if (from == float64 && to == word64) {
275 if (
kind == Kind::kBitcast) {
276 return __ Tuple(
__ Float64ExtractLowWord32(input),
277 __ Float64ExtractHighWord32(input));
280 if (from == word64 && to == float64) {
281 if (
kind == Kind::kBitcast) {
283 return __ BitcastWord32PairToFloat64(
284 __ template Projection<1>(input_w32p),
285 __ template Projection<0>(input_w32p));
288 if (from == word64 && to == word32 &&
kind == Kind::kTruncate) {
290 return __ template Projection<0>(input_w32p);
292 std::stringstream str;
293 str <<
"ChangeOp " <<
kind <<
" from " << from <<
" to " << to
294 <<
"not supported by int64 lowering";
295 FATAL(
"%s", str.str().c_str());
308 static_cast<uint32_t
>(
offset) +
static_cast<uint32_t
>(add_offset);
314 if (index.has_value()) {
315 new_index =
__ Word32Add(new_index.
value(), add_offset);
317 new_index =
__ Word32Constant(
sizeof(int32_t));
320 return {new_index, new_offset};
326 uint8_t element_scale) {
327 if (
kind.is_atomic) {
340 __ Word32Constant(0));
345 auto [high_index, high_offset] =
355 return Next::ReduceLoad(
base, index,
kind, loaded_rep, result_rep,
offset,
362 uint8_t element_size_log2,
363 bool maybe_initializing_or_transitioning,
367 auto [low, high] =
Unpack(value);
368 if (
kind.is_atomic) {
373 return __ AtomicWord32PairStore(
base, index, low, high,
offset);
377 write_barrier,
offset, element_size_log2,
378 maybe_initializing_or_transitioning,
379 maybe_indirect_pointer_tag);
381 auto [high_index, high_offset] =
385 write_barrier, high_offset, element_size_log2,
386 maybe_initializing_or_transitioning, maybe_indirect_pointer_tag);
389 return Next::ReduceStore(
base, index, value,
kind, stored_rep,
390 write_barrier,
offset, element_size_log2,
391 maybe_initializing_or_transitioning,
392 maybe_indirect_pointer_tag);
401 return Next::ReduceAtomicRMW(
base, index, value, expected, bin_op,
402 in_out_rep, memory_rep,
kind);
404 auto [value_low, value_high] =
Unpack(value);
407 if (bin_op == AtomicRMWOp::BinOp::kCompareExchange) {
408 auto [expected_low, expected_high] =
Unpack(expected.value());
409 return __ AtomicWord32PairCompareExchange(
410 base, index, value_low, value_high, expected_low, expected_high);
412 return __ AtomicWord32PairBinop(
base, index, value_low, value_high,
418 if (bin_op == AtomicRMWOp::BinOp::kCompareExchange) {
419 auto [expected_low, expected_high] =
Unpack(expected.value());
420 new_expected = expected_low;
422 return __ Tuple(Next::ReduceAtomicRMW(
423 base, index, value_low, new_expected, bin_op,
425 __ Word32Constant(0));
434 inputs_low.
reserve(inputs.size());
435 inputs_high.
reserve(inputs.size());
438 inputs_low.
push_back(
__ template Projection<0>(input_w32p));
439 inputs_high.
push_back(
__ template Projection<1>(input_w32p));
444 return Next::ReducePhi(inputs, rep);
454 return Next::ReducePendingLoopPhi(input, rep);
458 Block* output_graph_loop) {
463 __ MapToNewGraph(input_phi.
input(1))};
464 for (
size_t i = 0;
i < 2; ++
i) {
466 if (!output_graph_loop->
Contains(phi_index)) {
477 __ output_graph().template Replace<PhiOp>(
481 __ Projection(new_inputs[1],
i,
487 return Next::FixLoopPhi(input_phi, output_index, output_graph_loop);
492 if (
kind != Simd128SplatOp::Kind::kI64x2) {
493 return Next::ReduceSimd128Splat(input,
kind);
498 base, high, Simd128ReplaceLaneOp::Kind::kI32x4, 1);
500 Simd128ReplaceLaneOp::Kind::kI32x4, 3);
504 Simd128ExtractLaneOp::Kind
kind,
506 if (
kind != Simd128ExtractLaneOp::Kind::kI64x2) {
507 return Next::ReduceSimd128ExtractLane(input,
kind, lane);
510 input, Simd128ExtractLaneOp::Kind::kI32x4, 2 * lane));
512 input, Simd128ExtractLaneOp::Kind::kI32x4, 2 * lane + 1));
517 Simd128ReplaceLaneOp::Kind
kind,
520 if (
kind != Simd128ReplaceLaneOp::Kind::kI64x2) {
521 return Next::ReduceSimd128ReplaceLane(into, new_lane,
kind, lane);
525 into, low, Simd128ReplaceLaneOp::Kind::kI32x4, 2 * lane);
527 low_replaced, high, Simd128ReplaceLaneOp::Kind::kI32x4, 2 * lane + 1);
533 bool has_int64_input =
false;
538 has_int64_input =
true;
542 if (!has_int64_input) {
543 return Next::ReduceFrameState(inputs, inlined, data);
550 data->frame_state_info.function_info();
552 int lowered_local_count = function_info->
local_count();
554 for (
size_t i = inlined;
i < inputs.
size(); ++
i) {
558 size_t machine_type_index =
i - inlined;
560 data->machine_types[machine_type_index]) ==
569 ++lowered_parameter_count;
571 ++lowered_local_count;
575 builder.
AddInput(data->machine_types[machine_type_index], inputs[
i]);
578 Zone* zone = Asm().data()->compilation_zone();
580 compiler::FrameStateType::kLiftoffFunction, lowered_parameter_count,
588 function_info_lowered);
590 return Next::ReduceFrameState(
601 ValidateOpInputRep(
__ output_graph(), tuple->input(0), word32);
602 ValidateOpInputRep(
__ output_graph(), tuple->input(1), word32);
609 DCHECK_EQ(call.descriptor->descriptor->ReturnCount(), 2);
610 DCHECK_EQ(call.descriptor->descriptor->GetReturnType(0),
612 DCHECK_EQ(call.descriptor->descriptor->GetReturnType(1),
623 return {
__ template Projection<0>(input),
__ template Projection<1>(input)};
628 return __ Tuple(input,
__ Word32ShiftRightArithmetic(input, 31));
632 auto [low, high] =
Unpack(input);
634 IF (
__ Word32Equal(high, 0)) {
635 result =
__ Word32Add(32,
__ Word32CountLeadingZeros(low));
637 result =
__ Word32CountLeadingZeros(high);
644 DCHECK(SupportedOperations::word32_ctz());
645 auto [low, high] =
Unpack(input);
647 IF (
__ Word32Equal(low, 0)) {
648 result =
__ Word32Add(32,
__ Word32CountTrailingZeros(high));
650 result =
__ Word32CountTrailingZeros(low);
657 DCHECK(SupportedOperations::word32_popcnt());
658 auto [low, high] =
Unpack(input);
660 __ Word32Add(
__ Word32PopCount(low),
__ Word32PopCount(high)),
661 __ Word32Constant(0));
666 auto [left_low, left_high] =
Unpack(left);
667 auto [right_low, right_high] =
Unpack(right);
668 return __ Word32PairBinop(left_low, left_high, right_low, right_high,
kind);
673 auto [left_low, left_high] =
Unpack(left);
676 return __ Word32PairBinop(left_low, left_high, right, right_high,
kind);
680 auto [left_low, left_high] =
Unpack(left);
681 auto [right_low, right_high] =
Unpack(right);
682 V<Word32> low_result =
__ Word32BitwiseAnd(left_low, right_low);
683 V<Word32> high_result =
__ Word32BitwiseAnd(left_high, right_high);
684 return __ Tuple(low_result, high_result);
688 auto [left_low, left_high] =
Unpack(left);
689 auto [right_low, right_high] =
Unpack(right);
690 V<Word32> low_result =
__ Word32BitwiseOr(left_low, right_low);
691 V<Word32> high_result =
__ Word32BitwiseOr(left_high, right_high);
692 return __ Tuple(low_result, high_result);
696 auto [left_low, left_high] =
Unpack(left);
697 auto [right_low, right_high] =
Unpack(right);
698 V<Word32> low_result =
__ Word32BitwiseXor(left_low, right_low);
699 V<Word32> high_result =
__ Word32BitwiseXor(left_high, right_high);
700 return __ Tuple(low_result, high_result);
705 DCHECK(!SupportedOperations::word64_rol());
706 auto [left_low, left_high] =
Unpack(left);
708 uint32_t constant_shift = 0;
710 if (
matcher_.MatchIntegralWord32Constant(shift, &constant_shift)) {
712 uint32_t shift_value = constant_shift & 0x3F;
713 if (shift_value == 0) {
717 if (shift_value == 32) {
719 return __ Tuple(left_high, left_low);
724 if (shift_value < 32) {
725 low_input = left_low;
726 high_input = left_high;
729 uint32_t masked_shift_value = shift_value & 0x1F;
730 V<Word32> masked_shift =
__ Word32Constant(masked_shift_value);
731 V<Word32> inv_shift =
__ Word32Constant(32 - masked_shift_value);
734 __ Word32ShiftRightLogical(low_input, masked_shift),
735 __ Word32ShiftLeft(high_input, inv_shift));
737 __ Word32ShiftRightLogical(high_input, masked_shift),
738 __ Word32ShiftLeft(low_input, inv_shift));
739 return __ Tuple(low_node, high_node);
743 if (!SupportedOperations::word32_shift_is_safe()) {
745 safe_shift =
__ Word32BitwiseAnd(shift, 0x1F);
749 __ Word32ShiftRightLogical(all_bits_set, safe_shift), all_bits_set);
750 V<Word32> bit_mask =
__ Word32BitwiseXor(inv_mask, all_bits_set);
752 V<Word32> less_than_32 =
__ Int32LessThan(shift, 32);
760 var_high = left_high;
763 V<Word32> rotate_low =
__ Word32RotateRight(var_low, safe_shift);
764 V<Word32> rotate_high =
__ Word32RotateRight(var_high, safe_shift);
767 __ Word32BitwiseOr(
__ Word32BitwiseAnd(rotate_low, bit_mask),
768 __ Word32BitwiseAnd(rotate_high, inv_mask));
770 __ Word32BitwiseOr(
__ Word32BitwiseAnd(rotate_high, bit_mask),
771 __ Word32BitwiseAnd(rotate_low, inv_mask));
772 return __ Tuple(low_node, high_node);
783 size_t i64_params = 0;
784 for (
size_t i = 0;
i < param_count; ++
i) {
788 size_t return_count = call_descriptor->
ReturnCount();
789 size_t i64_returns = 0;
790 for (
size_t i = 0;
i < return_count; ++
i) {
794 if (i64_params + i64_returns == 0) {
796 return is_tail_call ? Next::ReduceTailCall(callee, arguments, descriptor)
797 : Next::ReduceCall(callee, frame_state, arguments,
798 descriptor, effects);
807 if (maybe_special_replacement) call_descriptor = maybe_special_replacement;
810 GetI32WasmCallDescriptor(
__ graph_zone(), call_descriptor);
815 lowered_args.
reserve(param_count + i64_params);
817 DCHECK_EQ(param_count, arguments.size());
818 for (
size_t i = 0;
i < param_count; ++
i) {
821 auto [low, high] =
Unpack(arguments[
i]);
829 auto lowered_ts_descriptor =
835 lowered_ts_descriptor)
836 : Next::ReduceCall(callee, frame_state,
838 lowered_ts_descriptor, effects);
843 if (i64_returns == 0 || return_count == 0) {
845 }
else if (return_count == 1) {
864 tuple_inputs.
reserve(return_count);
865 size_t projection_index = 0;
867 for (
size_t i = 0;
i < return_count; ++
i) {
872 __ Tuple(
__ Projection(call, projection_index, word32),
873 __ Projection(call, projection_index + 1, word32)));
874 projection_index += 2;
877 call, projection_index++,
881 DCHECK_EQ(projection_index, return_count + i64_returns);
888 int32_t new_index = 0;
889 for (
size_t i = 0;
i <
sig_->parameter_count(); ++
i) {
900 return rep == MachineRepresentation::kWord64;
#define REDUCE(operation)
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
void reserve(size_t new_capacity)
constexpr MachineRepresentation representation() const
static constexpr MachineType Int32()
void push_back(const T &value)
size_t ParameterCount() const
MachineType GetParameterType(size_t index) const
size_t ReturnCount() const
MachineType GetReturnType(size_t index) const
uint16_t max_arguments() const
uint16_t parameter_count() const
uint32_t wasm_function_index() const
IndirectHandle< SharedFunctionInfo > shared_info() const
uint32_t wasm_liftoff_frame_size() const
OutputFrameStateCombine state_combine() const
BytecodeOffset bailout_id() const
V8_EXPORT_PRIVATE compiler::CallDescriptor * GetLoweredCallDescriptor(const compiler::CallDescriptor *original)
bool Contains(OpIndex op_idx) const
const FrameStateData * AllocateFrameStateData(const FrameStateInfo &info, Zone *zone)
void AddParentFrameState(V< FrameState > parent)
base::Vector< const OpIndex > Inputs()
void AddInput(MachineType type, OpIndex input)
OpIndex REDUCE TailCall(OpIndex callee, base::Vector< const OpIndex > arguments, const TSCallDescriptor *descriptor)
OpIndex REDUCE Parameter(int32_t parameter_index, RegisterRepresentation rep, const char *debug_name="")
V< None > REDUCE Store(OpIndex base, OptionalOpIndex index, OpIndex value, StoreOp::Kind kind, MemoryRepresentation stored_rep, WriteBarrierKind write_barrier, int32_t offset, uint8_t element_size_log2, bool maybe_initializing_or_transitioning, IndirectPointerTag maybe_indirect_pointer_tag)
V< Word32Pair > LowerClz(V< Word32Pair > input)
bool CheckPairOrPairOp(V< Word32Pair > input)
V< Any > LowerCall(V< CallTarget > callee, OptionalV< FrameState > frame_state, base::Vector< const OpIndex > arguments, const TSCallDescriptor *descriptor, OpEffects effects, bool is_tail_call)
V< Simd128 > REDUCE Simd128ReplaceLane(V< Simd128 > into, V< Any > new_lane, Simd128ReplaceLaneOp::Kind kind, uint8_t lane)
OpIndex REDUCE AtomicRMW(OpIndex base, OpIndex index, OpIndex value, OptionalOpIndex expected, AtomicRMWOp::BinOp bin_op, RegisterRepresentation in_out_rep, MemoryRepresentation memory_rep, MemoryAccessKind kind)
OpIndex REDUCE PendingLoopPhi(OpIndex input, RegisterRepresentation rep)
ZoneVector< int32_t > param_index_map_
std::pair< V< Word32 >, V< Word32 > > Unpack(V< Word32Pair > input)
V< Word32Pair > LowerPairBinOp(V< Word32Pair > left, V< Word32Pair > right, Word32PairBinopOp::Kind kind)
V< Any > REDUCE Simd128ExtractLane(V< Simd128 > input, Simd128ExtractLaneOp::Kind kind, uint8_t lane)
void FixLoopPhi(const PhiOp &input_phi, OpIndex output_index, Block *output_graph_loop)
V< Word32 > REDUCE Comparison(V< Any > left, V< Any > right, ComparisonOp::Kind kind, RegisterRepresentation rep)
OpIndex REDUCE Change(OpIndex input, ChangeOp::Kind kind, ChangeOp::Assumption assumption, RegisterRepresentation from, RegisterRepresentation to)
Word32OrWord32Pair REDUCE WordUnary(Word32OrWord32Pair input, WordUnaryOp::Kind kind, WordRepresentation rep)
OpIndex REDUCE Load(OpIndex base, OptionalOpIndex index, LoadOp::Kind kind, MemoryRepresentation loaded_rep, RegisterRepresentation result_rep, int32_t offset, uint8_t element_scale)
void InitializeIndexMaps()
V< None > REDUCE Return(V< Word32 > pop_count, base::Vector< const OpIndex > return_values, bool spill_caller_frame_slots)
OpIndex REDUCE Phi(base::Vector< const OpIndex > inputs, RegisterRepresentation rep)
V< Word32Pair > LowerBitwiseXor(V< Word32Pair > left, V< Word32Pair > right)
V< Simd128 > REDUCE Simd128Splat(V< Any > input, Simd128SplatOp::Kind kind)
const Signature< MachineRepresentation > * sig_
Word32OrWord32Pair REDUCE WordBinop(Word32OrWord32Pair left, Word32OrWord32Pair right, WordBinopOp::Kind kind, WordRepresentation rep)
V< Word32Pair > LowerPairShiftOp(V< Word32Pair > left, V< Word32 > right, Word32PairBinopOp::Kind kind)
std::pair< OptionalV< Word32 >, int32_t > IncreaseOffset(OptionalV< Word32 > index, int32_t offset, int32_t add_offset, bool tagged_base)
V< Word32Pair > LowerPopCount(V< Word32Pair > input)
V< Word32Pair > LowerRotateRight(V< Word32Pair > left, V< Word32 > right)
const OperationMatcher & matcher_
V< Word32Pair > LowerCtz(V< Word32Pair > input)
V< Word32Pair > LowerBitwiseAnd(V< Word32Pair > left, V< Word32Pair > right)
V< Word32Pair > LowerSignExtend(V< Word32 > input)
V< Word32Pair > LowerBitwiseOr(V< Word32Pair > left, V< Word32Pair > right)
static constexpr MemoryRepresentation Int32()
static constexpr MemoryRepresentation Int64()
static constexpr MemoryRepresentation Uint64()
static constexpr OpIndex Invalid()
constexpr V< T > value() const
static OptionalV Nullopt()
static constexpr RegisterRepresentation FromMachineType(MachineType type)
static constexpr RegisterRepresentation FromMachineRepresentation(MachineRepresentation rep)
static constexpr RegisterRepresentation Word32()
static constexpr RegisterRepresentation Float64()
static constexpr RegisterRepresentation Word64()
static V< T > Cast(V< U > index)
static constexpr WordRepresentation Word64()
compiler::WasmCallDescriptors * call_descriptors()
#define TURBOSHAFT_REDUCER_BOILERPLATE(Name)
ZoneVector< RpoNumber > & result
constexpr Vector< T > VectorOf(T *start, size_t size)
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Signature< MachineRepresentation > * CreateMachineSignature(Zone *zone, const Signature< T > *sig, wasm::CallOrigin origin)
WasmEngine * GetWasmEngine()
constexpr NullMaybeHandleType kNullMaybeHandle
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
#define DCHECK_NE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
@ kUnsignedLessThanOrEqual
static constexpr bool OffsetIsValid(int32_t offset, bool tagged_base)
V8_INLINE OpIndex & input(size_t i)
const uint16_t input_count
RegisterRepresentation rep
RegisterRepresentation rep
const CallDescriptor * descriptor
static const TSCallDescriptor * Create(const CallDescriptor *descriptor, CanThrow can_throw, LazyDeoptOnThrow lazy_deopt_on_throw, Zone *graph_zone, const JSWasmCallParameters *js_wasm_call_parameters=nullptr)