38#if V8_ENABLE_WEBASSEMBLY
46using namespace turboshaft;
51 explicit LoadStoreView(
const Operation& op) {
52 DCHECK(op.Is<LoadOp>() || op.Is<StoreOp>());
53 if (
const LoadOp* load = op.TryCast<LoadOp>()) {
55 index = load->index();
59 const StoreOp& store = op.Cast<StoreOp>();
61 index = store.index();
70struct ScaledIndexMatch {
76struct BaseWithScaledIndexAndDisplacementMatch {
80 int32_t displacement = 0;
86 OpIndex* index,
int*
scale,
bool* power_of_two_plus_one) {
92 const ConstantOp* constant = op.TryCast<ConstantOp>();
93 if (constant ==
nullptr)
return false;
94 if (constant->kind != ConstantOp::Kind::kWord32)
return false;
96 uint64_t value = constant->integral();
97 if (plus_one) *plus_one =
false;
98 if (value == 1)
return (
scale = 0),
true;
99 if (value == 2)
return (
scale = 1),
true;
100 if (value == 4)
return (
scale = 2),
true;
101 if (value == 8)
return (
scale = 3),
true;
102 if (plus_one ==
nullptr)
return false;
104 if (value == 3)
return (
scale = 1),
true;
105 if (value == 5)
return (
scale = 2),
true;
106 if (value == 9)
return (
scale = 3),
true;
110 const Operation& op = selector->Get(node);
111 if (
const WordBinopOp* binop = op.TryCast<WordBinopOp>()) {
112 if (binop->kind != WordBinopOp::Kind::kMul)
return false;
113 if (MatchScaleConstant(selector->Get(binop->right()), *
scale,
114 power_of_two_plus_one)) {
115 *index = binop->left();
118 if (MatchScaleConstant(selector->Get(binop->left()), *
scale,
119 power_of_two_plus_one)) {
120 *index = binop->right();
125 if (shift->kind != ShiftOp::Kind::kShiftLeft)
return false;
127 if (selector->MatchIntegralWord32Constant(shift->right(), &scale_value)) {
128 if (scale_value < 0 || scale_value > 3)
return false;
129 *index = shift->left();
130 *
scale =
static_cast<int>(scale_value);
131 if (power_of_two_plus_one) *power_of_two_plus_one =
false;
139 InstructionSelectorT* selector,
OpIndex node,
140 bool allow_power_of_two_plus_one) {
141 ScaledIndexMatch match;
142 bool plus_one =
false;
144 allow_power_of_two_plus_one ? &plus_one :
nullptr)) {
145 match.base = plus_one ? match.index :
OpIndex{};
152std::optional<BaseWithScaledIndexAndDisplacementMatch>
153TryMatchBaseWithScaledIndexAndDisplacementForWordBinop(
155 BaseWithScaledIndexAndDisplacementMatch
result;
158 auto OwnedByAddressingOperand = [](
OpIndex) {
166 OwnedByAddressingOperand(left)) {
170 if (
const WordBinopOp* right_binop =
171 selector->Get(right).TryCast<WordBinopOp>()) {
173 if (right_binop->kind == WordBinopOp::Kind::kSub &&
174 OwnedByAddressingOperand(right)) {
175 if (!selector->MatchIntegralWord32Constant(right_binop->right(),
179 result.base = right_binop->left();
184 if (right_binop->kind == WordBinopOp::Kind::kAdd &&
185 OwnedByAddressingOperand(right)) {
186 if (selector->MatchIntegralWord32Constant(right_binop->right(),
189 result.base = right_binop->left();
190 }
else if (selector->MatchIntegralWord32Constant(
191 right_binop->left(), &
result.displacement)) {
193 result.base = right_binop->right();
204 if (selector->MatchIntegralWord32Constant(right, &
result.displacement)) {
216 if (
const WordBinopOp* left_add = selector->Get(left).TryCast<WordBinopOp>();
217 left_add && left_add->kind == WordBinopOp::Kind::kAdd &&
218 OwnedByAddressingOperand(left)) {
221 &
result.scale,
nullptr)) {
224 if (selector->MatchIntegralWord32Constant(left_add->right(),
230 if (selector->MatchIntegralWord32Constant(right, &
result.displacement)) {
231 result.base = left_add->right();
248 if (selector->MatchIntegralWord32Constant(right, &
result.displacement)) {
260std::optional<BaseWithScaledIndexAndDisplacementMatch>
261TryMatchBaseWithScaledIndexAndDisplacement(InstructionSelectorT* selector,
280 BaseWithScaledIndexAndDisplacementMatch
result;
283 const Operation& op = selector->Get(node);
284 if (
const LoadOp* load = op.TryCast<LoadOp>()) {
285 result.base = load->base();
286 result.index = load->index().value_or_invalid();
287 result.scale = load->element_size_log2;
288 result.displacement = load->offset;
291 }
else if (
const StoreOp* store = op.TryCast<StoreOp>()) {
292 result.base = store->base();
293 result.index = store->index().value_or_invalid();
294 result.scale = store->element_size_log2;
295 result.displacement = store->offset;
298 }
else if (op.Is<WordBinopOp>()) {
300#ifdef V8_ENABLE_WEBASSEMBLY
301 }
else if (
const Simd128LaneMemoryOp* lane_op =
302 op.TryCast<Simd128LaneMemoryOp>()) {
303 result.base = lane_op->base();
304 result.index = lane_op->index();
309 }
else if (
const Simd128LoadTransformOp* load_transform =
310 op.TryCast<Simd128LoadTransformOp>()) {
311 result.base = load_transform->base();
312 result.index = load_transform->index();
316 DCHECK(!load_transform->load_kind.tagged_base);
323 const WordBinopOp& binop = op.Cast<WordBinopOp>();
326 return TryMatchBaseWithScaledIndexAndDisplacementForWordBinop(selector, left,
346 if (!
selector()->CanCover(node, input))
return false;
347 if (effect_level !=
selector()->GetEffectLevel(input)) {
376 switch (constant->kind) {
377 case ConstantOp::Kind::kWord32:
378 case ConstantOp::Kind::kRelocatableWasmCall:
379 case ConstantOp::Kind::kRelocatableWasmStubCall:
380 case ConstantOp::Kind::kSmi:
382 case ConstantOp::Kind::kNumber:
383 return constant->number().get_bits() == 0;
394 if (constant.kind == ConstantOp::Kind::kWord32)
return constant.
word32();
395 if (constant.kind == ConstantOp::Kind::kSmi) {
396 return static_cast<int32_t
>(constant.smi().ptr());
398 DCHECK_EQ(constant.kind, ConstantOp::Kind::kNumber);
399 DCHECK_EQ(constant.number().get_bits(), 0);
405 return std::numeric_limits<int32_t>::min() < value &&
406 value <= std::numeric_limits<int32_t>::max();
420 if (constant->kind == ConstantOp::Kind::kWord32) {
424 }
else if (constant->kind == ConstantOp::Kind::kSmi) {
426 displacement,
static_cast<int32_t
>(constant->smi().ptr()));
435 inputs[(*input_count)++] =
439 static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
440 kMode_MR4I, kMode_MR8I};
441 mode = kMRnI_modes[
scale];
444 kMode_MR4, kMode_MR8};
445 mode = kMRn_modes[
scale];
458 inputs[(*input_count)++] =
463 kMode_M4I, kMode_M8I};
464 mode = kMnI_modes[
scale];
468 mode = kMn_modes[
scale];
483 LoadStoreView load_or_store(op);
486 !load_or_store.index.valid()) {
487 if (
selector()->CanAddressRelativeToRootsRegister(reference)) {
488 const ptrdiff_t delta =
489 load_or_store.offset +
492 if (is_int32(delta)) {
493 inputs[(*input_count)++] =
501 auto m = TryMatchBaseWithScaledIndexAndDisplacement(
selector(), node);
503 if (
m->base.valid() &&
508 inputs[(*input_count)++] =
513 m->displacement,
m->displacement_mode,
514 inputs, input_count, register_mode);
515 }
else if (!
m->base.valid() &&
551 switch (load_rep.representation()) {
560 opcode = load_rep.IsSigned() ? kIA32Movsxbl : kIA32Movzxbl;
563 opcode = load_rep.IsSigned() ? kIA32Movsxwl : kIA32Movzxwl;
572 opcode = kIA32Movdqu;
592 IA32OperandGeneratorT g(selector);
593 OpIndex input = selector->input_at(node, 0);
595 InstructionOperand input_op =
596 opcode == kIA32Movsxbl ? g.UseFixed(input, eax) : g.Use(input);
597 selector->Emit(opcode, g.DefineAsRegister(node), input_op);
600void VisitROWithTemp(InstructionSelectorT* selector,
OpIndex node,
602 IA32OperandGeneratorT g(selector);
603 InstructionOperand temps[] = {g.TempRegister()};
604 selector->Emit(opcode, g.DefineAsRegister(node),
605 g.Use(selector->input_at(node, 0)),
arraysize(temps), temps);
608void VisitROWithTempSimd(InstructionSelectorT* selector,
OpIndex node,
610 IA32OperandGeneratorT g(selector);
611 InstructionOperand temps[] = {g.TempSimd128Register()};
612 selector->Emit(opcode, g.DefineAsRegister(node),
613 g.UseUniqueRegister(selector->input_at(node, 0)),
619 IA32OperandGeneratorT g(selector);
620 selector->Emit(opcode, g.DefineAsRegister(node),
621 g.UseRegister(selector->input_at(node, 0)));
624void VisitRROFloat(InstructionSelectorT* selector,
OpIndex node,
626 IA32OperandGeneratorT g(selector);
627 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
628 InstructionOperand operand1 = g.Use(selector->input_at(node, 1));
629 if (selector->IsSupported(AVX)) {
630 selector->Emit(opcode, g.DefineAsRegister(node), operand0, operand1);
632 selector->Emit(opcode, g.DefineSameAsFirst(node), operand0, operand1);
639void VisitFloatUnop(InstructionSelectorT* selector,
OpIndex node,
OpIndex input,
641 IA32OperandGeneratorT g(selector);
642 InstructionOperand temps[] = {g.TempRegister()};
644 if (selector->IsSupported(AVX)) {
645 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(input),
648 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(input),
653#if V8_ENABLE_WEBASSEMBLY
655void VisitRRSimd(InstructionSelectorT* selector,
OpIndex node,
657 IA32OperandGeneratorT g(selector);
658 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
659 if (selector->IsSupported(AVX)) {
660 selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0);
662 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0);
666void VisitRRSimd(InstructionSelectorT* selector,
OpIndex node,
668 VisitRRSimd(selector, node, opcode, opcode);
675void VisitRROSimd(InstructionSelectorT* selector,
OpIndex node,
677 IA32OperandGeneratorT g(selector);
678 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
679 if (selector->IsSupported(AVX)) {
680 selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0,
681 g.UseRegister(selector->input_at(node, 1)));
683 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0,
684 g.UseRegister(selector->input_at(node, 1)));
688void VisitRRRSimd(InstructionSelectorT* selector,
OpIndex node,
690 IA32OperandGeneratorT g(selector);
691 InstructionOperand dst = selector->IsSupported(AVX)
692 ? g.DefineAsRegister(node)
693 : g.DefineSameAsFirst(node);
694 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
695 InstructionOperand operand1 = g.UseRegister(selector->input_at(node, 1));
696 selector->Emit(opcode, dst, operand0, operand1);
699int32_t GetSimdLaneConstant(InstructionSelectorT* selector,
OpIndex node) {
700 const Simd128ExtractLaneOp& op =
705void VisitRRISimd(InstructionSelectorT* selector,
OpIndex node,
707 IA32OperandGeneratorT g(selector);
708 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
709 InstructionOperand operand1 =
710 g.UseImmediate(GetSimdLaneConstant(selector, node));
713 InstructionOperand dest = opcode == kIA32I8x16ExtractLaneS
714 ? g.DefineAsFixed(node, eax)
715 : g.DefineAsRegister(node);
716 selector->Emit(opcode, dest, operand0, operand1);
719void VisitRRISimd(InstructionSelectorT* selector,
OpIndex node,
721 IA32OperandGeneratorT g(selector);
722 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
723 InstructionOperand operand1 =
724 g.UseImmediate(GetSimdLaneConstant(selector, node));
725 if (selector->IsSupported(AVX)) {
726 selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
728 selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
732void VisitRROSimdShift(InstructionSelectorT* selector,
OpIndex node,
734 IA32OperandGeneratorT g(selector);
735 if (g.CanBeImmediate(selector->input_at(node, 1))) {
736 selector->Emit(opcode, g.DefineSameAsFirst(node),
737 g.UseRegister(selector->input_at(node, 0)),
738 g.UseImmediate(selector->input_at(node, 1)));
740 InstructionOperand operand0 =
741 g.UseUniqueRegister(selector->input_at(node, 0));
742 InstructionOperand operand1 =
743 g.UseUniqueRegister(selector->input_at(node, 1));
744 InstructionOperand temps[] = {g.TempSimd128Register(), g.TempRegister()};
745 selector->Emit(opcode, g.DefineSameAsFirst(node), operand0, operand1,
752 IA32OperandGeneratorT g(selector);
753 selector->Emit(opcode, g.DefineAsRegister(node),
754 g.UseRegister(selector->input_at(node, 0)),
755 g.UseRegister(selector->input_at(node, 1)),
756 g.UseRegister(selector->input_at(node, 2)));
759void VisitI8x16Shift(InstructionSelectorT* selector,
OpIndex node,
761 IA32OperandGeneratorT g(selector);
763 ? g.UseRegister(node)
764 : g.DefineSameAsFirst(node);
766 if (g.CanBeImmediate(selector->input_at(node, 1))) {
767 if (opcode == kIA32I8x16ShrS) {
768 selector->Emit(opcode, output, g.UseRegister(selector->input_at(node, 0)),
769 g.UseImmediate(selector->input_at(node, 1)));
771 InstructionOperand temps[] = {g.TempRegister()};
772 selector->Emit(opcode, output, g.UseRegister(selector->input_at(node, 0)),
773 g.UseImmediate(selector->input_at(node, 1)),
777 InstructionOperand operand0 =
778 g.UseUniqueRegister(selector->input_at(node, 0));
779 InstructionOperand operand1 =
780 g.UseUniqueRegister(selector->input_at(node, 1));
781 InstructionOperand temps[] = {g.TempRegister(), g.TempSimd128Register()};
782 selector->Emit(opcode, output, operand0, operand1,
arraysize(temps), temps);
789void InstructionSelectorT::VisitStackSlot(
OpIndex node) {
792 stack_slot.is_tagged);
795 Emit(kArchStackSlot, g.DefineAsRegister(node),
796 sequence()->AddImmediate(Constant(slot)), 0,
nullptr);
799void InstructionSelectorT::VisitAbortCSADcheck(
OpIndex node) {
800 IA32OperandGeneratorT g(
this);
801 Emit(kArchAbortCSADcheck, g.NoOutput(),
802 g.UseFixed(this->input_at(node, 0), edx));
805#if V8_ENABLE_WEBASSEMBLY
807void InstructionSelectorT::VisitLoadLane(
OpIndex node) {
810 const Simd128LaneMemoryOp& load =
813 switch (load.lane_kind) {
814 case Simd128LaneMemoryOp::LaneKind::k8:
817 case Simd128LaneMemoryOp::LaneKind::k16:
820 case Simd128LaneMemoryOp::LaneKind::k32:
823 case Simd128LaneMemoryOp::LaneKind::k64:
834 DCHECK(!load.kind.maybe_unaligned);
836 DCHECK(!load.kind.with_trap_handler);
838 IA32OperandGeneratorT g(
this);
840 ? g.DefineAsRegister(node)
841 : g.DefineSameAsFirst(node)};
845 InstructionOperand
inputs[5];
852 g.GetEffectiveAddressMemoryOperand(node,
inputs, &input_count);
861 const Simd128LoadTransformOp& op =
862 this->
Get(node).Cast<Simd128LoadTransformOp>();
864 switch (op.transform_kind) {
865 case Simd128LoadTransformOp::TransformKind::k8x8S:
866 opcode = kIA32S128Load8x8S;
868 case Simd128LoadTransformOp::TransformKind::k8x8U:
869 opcode = kIA32S128Load8x8U;
871 case Simd128LoadTransformOp::TransformKind::k16x4S:
872 opcode = kIA32S128Load16x4S;
874 case Simd128LoadTransformOp::TransformKind::k16x4U:
875 opcode = kIA32S128Load16x4U;
877 case Simd128LoadTransformOp::TransformKind::k32x2S:
878 opcode = kIA32S128Load32x2S;
880 case Simd128LoadTransformOp::TransformKind::k32x2U:
881 opcode = kIA32S128Load32x2U;
883 case Simd128LoadTransformOp::TransformKind::k8Splat:
884 opcode = kIA32S128Load8Splat;
886 case Simd128LoadTransformOp::TransformKind::k16Splat:
887 opcode = kIA32S128Load16Splat;
889 case Simd128LoadTransformOp::TransformKind::k32Splat:
890 opcode = kIA32S128Load32Splat;
892 case Simd128LoadTransformOp::TransformKind::k64Splat:
893 opcode = kIA32S128Load64Splat;
895 case Simd128LoadTransformOp::TransformKind::k32Zero:
898 case Simd128LoadTransformOp::TransformKind::k64Zero:
904 DCHECK(!op.load_kind.maybe_unaligned);
906 DCHECK(!op.load_kind.with_trap_handler);
914 IA32OperandGeneratorT g(
this);
915 InstructionOperand outputs[1];
916 outputs[0] = g.DefineAsRegister(node);
917 InstructionOperand
inputs[3];
920 g.GetEffectiveAddressMemoryOperand(value,
inputs, &input_count);
927 DCHECK(!load_rep.IsMapWord());
928 VisitLoad(node, node, GetLoadOpcode(load_rep));
931void InstructionSelectorT::VisitProtectedLoad(
OpIndex node) {
975 return kAtomicExchangeInt8;
977 return kAtomicExchangeInt16;
982 return kAtomicExchangeWord32;
990 IA32OperandGeneratorT g(selector);
992 OpIndex index = selector->input_at(node, 1);
993 OpIndex value = selector->input_at(node, 2);
997 ? g.UseFixed(value, edx)
998 : g.UseUniqueRegister(value);
999 InstructionOperand inputs[] = {
1000 value_operand, g.UseUniqueRegister(base),
1001 g.GetEffectiveIndexOperand(index, &addressing_mode)};
1002 InstructionOperand outputs[] = {
1005 ? g.DefineAsFixed(node, edx)
1006 : g.DefineSameAsFirst(node)};
1008 selector->Emit(code, 1, outputs,
arraysize(inputs), inputs);
1012 const TurboshaftAdapter::StoreView& store) {
1013 IA32OperandGeneratorT g(selector);
1017 OpIndex value = store.value();
1019 uint8_t element_size_log2 = store.element_size_log2();
1020 std::optional<AtomicMemoryOrder> atomic_order = store.memory_order();
1021 StoreRepresentation store_rep = store.stored_rep();
1025 const bool is_seqcst =
1033 !
v8_flags.disable_write_barriers) {
1036 InstructionOperand inputs[4];
1038 addressing_mode = g.GenerateMemoryOperandInputs(
1043 inputs[
input_count++] = g.UseUniqueRegister(value);
1046 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()};
1047 size_t const temp_count =
arraysize(temps);
1049 : kArchStoreWithWriteBarrier;
1052 selector->Emit(code, 0,
nullptr, input_count, inputs, temp_count, temps);
1054 InstructionOperand inputs[4];
1057 InstructionOperand outputs[1];
1058 size_t output_count = 0;
1069 outputs[output_count++] = g.DefineAsFixed(store, edx);
1071 inputs[
input_count++] = g.UseUniqueRegister(value);
1072 outputs[output_count++] = g.DefineSameAsFirst(store);
1074 addressing_mode = g.GetEffectiveAddressMemoryOperand(
1075 store, inputs, &input_count,
1077 opcode = GetSeqCstStoreOpcode(rep);
1081 InstructionOperand val;
1082 if (g.CanBeImmediate(value)) {
1083 val = g.UseImmediate(value);
1086 val = g.UseByteRegister(value);
1088 val = g.UseUniqueRegister(value);
1090 addressing_mode = g.GetEffectiveAddressMemoryOperand(
1091 store, inputs, &input_count,
1094 opcode = GetStoreOpcode(rep);
1098 selector->Emit(code, output_count, outputs, input_count, inputs);
1106void InstructionSelectorT::VisitStore(
OpIndex node) {
1110void InstructionSelectorT::VisitProtectedStore(
OpIndex node) {
1115#if V8_ENABLE_WEBASSEMBLY
1117void InstructionSelectorT::VisitStoreLane(
OpIndex node) {
1118 IA32OperandGeneratorT g(
this);
1121 const Simd128LaneMemoryOp& store =
1124 switch (store.lane_kind) {
1125 case Simd128LaneMemoryOp::LaneKind::k8:
1128 case Simd128LaneMemoryOp::LaneKind::k16:
1131 case Simd128LaneMemoryOp::LaneKind::k32:
1132 opcode = kIA32S128Store32Lane;
1134 case Simd128LaneMemoryOp::LaneKind::k64:
1144 InstructionOperand
inputs[4];
1147 g.GetEffectiveAddressMemoryOperand(node,
inputs, &input_count);
1150 InstructionOperand value_operand = g.UseRegister(this->
input_at(node, 2));
1169 IA32OperandGeneratorT g(selector);
1170 auto left = selector->input_at(node, 0);
1171 auto right = selector->input_at(node, 1);
1172 InstructionOperand inputs[6];
1174 InstructionOperand outputs[1];
1175 size_t output_count = 0;
1178 if (left == right) {
1186 InstructionOperand
const input = g.UseRegister(left);
1189 }
else if (g.CanBeImmediate(right)) {
1193 int effect_level = selector->GetEffectLevel(node, cont);
1194 if (selector->IsCommutative(node) && g.CanBeBetterLeftOperand(right) &&
1195 (!g.CanBeBetterLeftOperand(left) ||
1196 !g.CanBeMemoryOperand(opcode, node, right, effect_level))) {
1197 std::swap(left, right);
1199 if (g.CanBeMemoryOperand(opcode, node, right, effect_level)) {
1202 g.GetEffectiveAddressMemoryOperand(right, inputs, &input_count);
1210 outputs[output_count++] = g.DefineSameAsFirst(node);
1217 selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
1223 FlagsContinuationT cont;
1229void InstructionSelectorT::VisitWord32And(
OpIndex node) {
1233void InstructionSelectorT::VisitWord32Or(
OpIndex node) {
1237void InstructionSelectorT::VisitWord32Xor(
OpIndex node) {
1238 IA32OperandGeneratorT g(
this);
1243 Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(binop.left()));
1250 OpIndex node, FlagsContinuation* cont) {
1259 IA32OperandGeneratorT g(
this);
1262 InstructionOperand*
const outputs =
nullptr;
1263 const int output_count = 0;
1268 InstructionOperand temps[] = {g.TempRegister()};
1275 if (g.CanBeMemoryOperand(kIA32Cmp, node, value, effect_level)) {
1279 static constexpr int kMaxInputCount = 3;
1282 InstructionOperand
inputs[kMaxInputCount];
1283 AddressingMode addressing_mode = g.GetEffectiveAddressMemoryOperand(
1284 value,
inputs, &input_count, register_mode);
1289 temp_count, temps, cont);
1291 InstructionOperand
inputs[] = {
1292 g.UseRegisterWithMode(value, register_mode)};
1295 temp_count, temps, cont);
1304 auto left = selector->
input_at(node, 0);
1305 auto right = selector->
input_at(node, 1);
1318void VisitMulHigh(InstructionSelectorT* selector,
OpIndex node,
1320 IA32OperandGeneratorT g(selector);
1321 InstructionOperand temps[] = {g.TempRegister(eax)};
1322 selector->Emit(opcode, g.DefineAsFixed(node, edx),
1323 g.UseFixed(selector->input_at(node, 0), eax),
1324 g.UseUniqueRegister(selector->input_at(node, 1)),
1329 IA32OperandGeneratorT g(selector);
1330 InstructionOperand temps[] = {g.TempRegister(edx)};
1331 selector->Emit(opcode, g.DefineAsFixed(node, eax),
1332 g.UseFixed(selector->input_at(node, 0), eax),
1333 g.UseUnique(selector->input_at(node, 1)),
arraysize(temps),
1338 IA32OperandGeneratorT g(selector);
1339 InstructionOperand temps[] = {g.TempRegister(eax)};
1340 selector->Emit(opcode, g.DefineAsFixed(node, edx),
1341 g.UseFixed(selector->input_at(node, 0), eax),
1342 g.UseUnique(selector->input_at(node, 1)),
arraysize(temps),
1347template <
typename Displacement>
1351 IA32OperandGeneratorT g(selector);
1352 InstructionOperand inputs[4];
1361 InstructionOperand outputs[1];
1362 outputs[0] = g.DefineAsRegister(
result);
1366 selector->Emit(opcode, 1, outputs, input_count, inputs);
1371void InstructionSelectorT::VisitWord32Shl(
OpIndex node) {
1379void InstructionSelectorT::VisitWord32Shr(
OpIndex node) {
1383void InstructionSelectorT::VisitWord32Sar(
OpIndex node) {
1387void InstructionSelectorT::VisitInt32PairAdd(
OpIndex node) {
1388 IA32OperandGeneratorT g(
this);
1391 if (projection1.valid()) {
1394 InstructionOperand
inputs[] = {
1395 g.UseRegister(this->
input_at(node, 0)),
1396 g.UseUniqueRegisterOrSlotOrConstant(this->
input_at(node, 1)),
1397 g.UseRegister(this->
input_at(node, 2)),
1398 g.UseUniqueRegister(this->
input_at(node, 3))};
1400 InstructionOperand outputs[] = {g.DefineSameAsFirst(node),
1401 g.DefineAsRegister(projection1.value())};
1403 InstructionOperand temps[] = {g.TempRegister()};
1405 Emit(kIA32AddPair, 2, outputs, 4,
inputs, 1, temps);
1409 Emit(kIA32Add, g.DefineSameAsFirst(node),
1410 g.UseRegister(this->input_at(node, 0)),
1411 g.Use(this->input_at(node, 2)));
1415void InstructionSelectorT::VisitInt32PairSub(
OpIndex node) {
1416 IA32OperandGeneratorT g(
this);
1419 if (projection1.valid()) {
1422 InstructionOperand
inputs[] = {
1423 g.UseRegister(this->
input_at(node, 0)),
1424 g.UseUniqueRegisterOrSlotOrConstant(this->
input_at(node, 1)),
1425 g.UseRegister(this->
input_at(node, 2)),
1426 g.UseUniqueRegister(this->
input_at(node, 3))};
1428 InstructionOperand outputs[] = {g.DefineSameAsFirst(node),
1429 g.DefineAsRegister(projection1.value())};
1431 InstructionOperand temps[] = {g.TempRegister()};
1433 Emit(kIA32SubPair, 2, outputs, 4,
inputs, 1, temps);
1437 Emit(kIA32Sub, g.DefineSameAsFirst(node),
1438 g.UseRegister(this->input_at(node, 0)),
1439 g.Use(this->input_at(node, 2)));
1443void InstructionSelectorT::VisitInt32PairMul(
OpIndex node) {
1444 IA32OperandGeneratorT g(
this);
1447 if (projection1.valid()) {
1450 InstructionOperand
inputs[] = {
1451 g.UseUnique(this->
input_at(node, 0)),
1452 g.UseUniqueRegisterOrSlotOrConstant(this->
input_at(node, 1)),
1453 g.UseUniqueRegister(this->
input_at(node, 2)),
1454 g.UseFixed(this->
input_at(node, 3), ecx)};
1456 InstructionOperand outputs[] = {g.DefineAsFixed(node, eax),
1457 g.DefineAsFixed(projection1.value(), ecx)};
1459 InstructionOperand temps[] = {g.TempRegister(edx)};
1461 Emit(kIA32MulPair, 2, outputs, 4,
inputs, 1, temps);
1465 Emit(kIA32Imul, g.DefineSameAsFirst(node),
1466 g.UseRegister(this->input_at(node, 0)),
1467 g.Use(this->input_at(node, 2)));
1480 shift_operand = g.
UseFixed(shift, ecx);
1488 int32_t output_count = 0;
1489 int32_t temp_count = 0;
1492 if (projection1.
valid()) {
1498 selector->
Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
1501void InstructionSelectorT::VisitWord32PairShl(
OpIndex node) {
1505void InstructionSelectorT::VisitWord32PairShr(
OpIndex node) {
1509void InstructionSelectorT::VisitWord32PairSar(
OpIndex node) {
1513void InstructionSelectorT::VisitWord32Rol(
OpIndex node) {
1517void InstructionSelectorT::VisitWord32Ror(
OpIndex node) {
1521#define RO_OP_T_LIST(V) \
1522 V(Float32Sqrt, kIA32Float32Sqrt) \
1523 V(Float64Sqrt, kIA32Float64Sqrt) \
1524 V(ChangeInt32ToFloat64, kSSEInt32ToFloat64) \
1525 V(TruncateFloat32ToInt32, kIA32Float32ToInt32) \
1526 V(TruncateFloat64ToFloat32, kIA32Float64ToFloat32) \
1527 V(BitcastFloat32ToInt32, kIA32BitcastFI) \
1528 V(BitcastInt32ToFloat32, kIA32BitcastIF) \
1529 V(Float64ExtractLowWord32, kIA32Float64ExtractLowWord32) \
1530 V(Float64ExtractHighWord32, kIA32Float64ExtractHighWord32) \
1531 V(ChangeFloat64ToInt32, kIA32Float64ToInt32) \
1532 V(ChangeFloat32ToFloat64, kIA32Float32ToFloat64) \
1533 V(RoundInt32ToFloat32, kSSEInt32ToFloat32) \
1534 V(RoundFloat64ToInt32, kIA32Float64ToInt32) \
1535 V(Word32Clz, kIA32Lzcnt) \
1536 V(Word32Ctz, kIA32Tzcnt) \
1537 V(Word32Popcnt, kIA32Popcnt) \
1538 V(SignExtendWord8ToInt32, kIA32Movsxbl) \
1539 V(SignExtendWord16ToInt32, kIA32Movsxwl) \
1541#define RO_WITH_TEMP_OP_T_LIST(V) V(ChangeUint32ToFloat64, kIA32Uint32ToFloat64)
1543#define RO_WITH_TEMP_SIMD_OP_T_LIST(V) \
1544 V(TruncateFloat64ToUint32, kIA32Float64ToUint32) \
1545 V(TruncateFloat32ToUint32, kIA32Float32ToUint32) \
1546 V(ChangeFloat64ToUint32, kIA32Float64ToUint32)
1548#define RR_OP_T_LIST(V) \
1549 V(Float32RoundDown, kIA32Float32Round | MiscField::encode(kRoundDown)) \
1550 V(Float64RoundDown, kIA32Float64Round | MiscField::encode(kRoundDown)) \
1551 V(Float32RoundUp, kIA32Float32Round | MiscField::encode(kRoundUp)) \
1552 V(Float64RoundUp, kIA32Float64Round | MiscField::encode(kRoundUp)) \
1553 V(Float32RoundTruncate, kIA32Float32Round | MiscField::encode(kRoundToZero)) \
1554 V(Float64RoundTruncate, kIA32Float64Round | MiscField::encode(kRoundToZero)) \
1555 V(Float32RoundTiesEven, \
1556 kIA32Float32Round | MiscField::encode(kRoundToNearest)) \
1557 V(Float64RoundTiesEven, \
1558 kIA32Float64Round | MiscField::encode(kRoundToNearest)) \
1559 V(TruncateFloat64ToWord32, kArchTruncateDoubleToI) \
1560 IF_WASM(V, F32x4Ceil, kIA32F32x4Round | MiscField::encode(kRoundUp)) \
1561 IF_WASM(V, F32x4Floor, kIA32F32x4Round | MiscField::encode(kRoundDown)) \
1562 IF_WASM(V, F32x4Trunc, kIA32F32x4Round | MiscField::encode(kRoundToZero)) \
1563 IF_WASM(V, F32x4NearestInt, \
1564 kIA32F32x4Round | MiscField::encode(kRoundToNearest)) \
1565 IF_WASM(V, F64x2Ceil, kIA32F64x2Round | MiscField::encode(kRoundUp)) \
1566 IF_WASM(V, F64x2Floor, kIA32F64x2Round | MiscField::encode(kRoundDown)) \
1567 IF_WASM(V, F64x2Trunc, kIA32F64x2Round | MiscField::encode(kRoundToZero)) \
1568 IF_WASM(V, F64x2NearestInt, \
1569 kIA32F64x2Round | MiscField::encode(kRoundToNearest)) \
1570 IF_WASM(V, F64x2Sqrt, kIA32F64x2Sqrt)
1572#define RRO_FLOAT_OP_T_LIST(V) \
1573 V(Float32Add, kFloat32Add) \
1574 V(Float64Add, kFloat64Add) \
1575 V(Float32Sub, kFloat32Sub) \
1576 V(Float64Sub, kFloat64Sub) \
1577 V(Float32Mul, kFloat32Mul) \
1578 V(Float64Mul, kFloat64Mul) \
1579 V(Float32Div, kFloat32Div) \
1580 V(Float64Div, kFloat64Div)
1582#define FLOAT_UNOP_T_LIST(V) \
1583 V(Float32Abs, kFloat32Abs) \
1584 V(Float64Abs, kFloat64Abs) \
1585 V(Float32Neg, kFloat32Neg) \
1586 V(Float64Neg, kFloat64Neg) \
1587 IF_WASM(V, F32x4Abs, kFloat32Abs) \
1588 IF_WASM(V, F32x4Neg, kFloat32Neg) \
1589 IF_WASM(V, F64x2Abs, kFloat64Abs) \
1590 IF_WASM(V, F64x2Neg, kFloat64Neg)
1592#define RO_VISITOR(Name, opcode) \
1593 void InstructionSelectorT::Visit##Name(OpIndex node) { \
1594 VisitRO(this, node, opcode); \
1600#define RO_WITH_TEMP_VISITOR(Name, opcode) \
1601 void InstructionSelectorT::Visit##Name(OpIndex node) { \
1602 VisitROWithTemp(this, node, opcode); \
1605#undef RO_WITH_TEMP_VISITOR
1606#undef RO_WITH_TEMP_OP_T_LIST
1608#define RO_WITH_TEMP_SIMD_VISITOR(Name, opcode) \
1609 void InstructionSelectorT::Visit##Name(OpIndex node) { \
1610 VisitROWithTempSimd(this, node, opcode); \
1613#undef RO_WITH_TEMP_SIMD_VISITOR
1614#undef RO_WITH_TEMP_SIMD_OP_T_LIST
1616#define RR_VISITOR(Name, opcode) \
1617 void InstructionSelectorT::Visit##Name(OpIndex node) { \
1618 VisitRR(this, node, opcode); \
1624#define RRO_FLOAT_VISITOR(Name, opcode) \
1625 void InstructionSelectorT::Visit##Name(OpIndex node) { \
1626 VisitRROFloat(this, node, opcode); \
1629#undef RRO_FLOAT_VISITOR
1630#undef RRO_FLOAT_OP_T_LIST
1632#define FLOAT_UNOP_VISITOR(Name, opcode) \
1633 void InstructionSelectorT::Visit##Name(OpIndex node) { \
1634 DCHECK_EQ(this->value_input_count(node), 1); \
1635 VisitFloatUnop(this, node, this->input_at(node, 0), opcode); \
1638#undef FLOAT_UNOP_VISITOR
1639#undef FLOAT_UNOP_T_LIST
1641void InstructionSelectorT::VisitTruncateFloat64ToFloat16RawBits(
OpIndex node) {
1645void InstructionSelectorT::VisitChangeFloat16RawBitsToFloat64(
OpIndex node) {
1649void InstructionSelectorT::VisitWord32ReverseBits(
OpIndex node) {
1653void InstructionSelectorT::VisitWord64ReverseBytes(
OpIndex node) {
1657void InstructionSelectorT::VisitWord32ReverseBytes(
OpIndex node) {
1658 IA32OperandGeneratorT g(
this);
1660 Emit(kIA32Bswap, g.DefineSameAsFirst(node),
1661 g.UseRegister(this->input_at(node, 0)));
1664void InstructionSelectorT::VisitSimd128ReverseBytes(
OpIndex node) {
1668void InstructionSelectorT::VisitInt32Add(
OpIndex node) {
1669 IA32OperandGeneratorT g(
this);
1674 std::optional<BaseWithScaledIndexAndDisplacementMatch>
m =
1675 TryMatchBaseWithScaledIndexAndDisplacementForWordBinop(
this, left, right);
1676 if (
m.has_value()) {
1677 if (g.ValueFitsIntoImmediate(
m->displacement)) {
1678 EmitLea(
this, node,
m->index,
m->scale,
m->base,
m->displacement,
1679 m->displacement_mode);
1687void InstructionSelectorT::VisitInt32Sub(
OpIndex node) {
1688 IA32OperandGeneratorT g(
this);
1691 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(right));
1697void InstructionSelectorT::VisitInt32Mul(
OpIndex node) {
1702 IA32OperandGeneratorT g(
this);
1703 auto left = this->
input_at(node, 0);
1704 auto right = this->
input_at(node, 1);
1705 if (g.CanBeImmediate(right)) {
1706 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
1707 g.UseImmediate(right));
1709 if (g.CanBeBetterLeftOperand(right)) {
1710 std::swap(left, right);
1712 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
1717void InstructionSelectorT::VisitInt32MulHigh(
OpIndex node) {
1718 VisitMulHigh(
this, node, kIA32ImulHigh);
1721void InstructionSelectorT::VisitUint32MulHigh(
OpIndex node) {
1722 VisitMulHigh(
this, node, kIA32UmulHigh);
1725void InstructionSelectorT::VisitInt32Div(
OpIndex node) {
1726 VisitDiv(
this, node, kIA32Idiv);
1729void InstructionSelectorT::VisitUint32Div(
OpIndex node) {
1730 VisitDiv(
this, node, kIA32Udiv);
1733void InstructionSelectorT::VisitInt32Mod(
OpIndex node) {
1734 VisitMod(
this, node, kIA32Idiv);
1737void InstructionSelectorT::VisitUint32Mod(
OpIndex node) {
1738 VisitMod(
this, node, kIA32Udiv);
1741void InstructionSelectorT::VisitRoundUint32ToFloat32(
OpIndex node) {
1742 IA32OperandGeneratorT g(
this);
1743 InstructionOperand temps[] = {g.TempRegister()};
1744 Emit(kIA32Uint32ToFloat32, g.DefineAsRegister(node),
1745 g.Use(this->input_at(node, 0)),
arraysize(temps), temps);
1748void InstructionSelectorT::VisitFloat64Mod(
OpIndex node) {
1749 IA32OperandGeneratorT g(
this);
1750 InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister()};
1751 Emit(kIA32Float64Mod, g.DefineSameAsFirst(node),
1752 g.UseRegister(this->input_at(node, 0)),
1753 g.UseRegister(this->input_at(node, 1)),
arraysize(temps), temps);
1756void InstructionSelectorT::VisitFloat32Max(
OpIndex node) {
1757 IA32OperandGeneratorT g(
this);
1758 InstructionOperand temps[] = {g.TempRegister()};
1759 Emit(kIA32Float32Max, g.DefineSameAsFirst(node),
1760 g.UseRegister(this->input_at(node, 0)), g.Use(this->input_at(node, 1)),
1764void InstructionSelectorT::VisitFloat64Max(
OpIndex node) {
1765 IA32OperandGeneratorT g(
this);
1766 InstructionOperand temps[] = {g.TempRegister()};
1767 Emit(kIA32Float64Max, g.DefineSameAsFirst(node),
1768 g.UseRegister(this->input_at(node, 0)), g.Use(this->input_at(node, 1)),
1772void InstructionSelectorT::VisitFloat32Min(
OpIndex node) {
1773 IA32OperandGeneratorT g(
this);
1774 InstructionOperand temps[] = {g.TempRegister()};
1775 Emit(kIA32Float32Min, g.DefineSameAsFirst(node),
1776 g.UseRegister(this->input_at(node, 0)), g.Use(this->input_at(node, 1)),
1780void InstructionSelectorT::VisitFloat64Min(
OpIndex node) {
1781 IA32OperandGeneratorT g(
this);
1782 InstructionOperand temps[] = {g.TempRegister()};
1783 Emit(kIA32Float64Min, g.DefineSameAsFirst(node),
1784 g.UseRegister(this->input_at(node, 0)), g.Use(this->input_at(node, 1)),
1788void InstructionSelectorT::VisitFloat64RoundTiesAway(
OpIndex node) {
1794 IA32OperandGeneratorT g(
this);
1796 g.UseRegister(this->input_at(node, 0)),
1797 g.UseRegister(this->input_at(node, 1)))
1803 IA32OperandGeneratorT g(
this);
1805 g.UseRegister(this->input_at(node, 0)))
1812 LinkageLocation location) {}
1815 ZoneVector<PushParameter>* arguments,
const CallDescriptor* call_descriptor,
1817 IA32OperandGeneratorT g(
this);
1821 if (call_descriptor->IsCFunctionCall()) {
1822 InstructionOperand temps[] = {g.TempRegister()};
1823 size_t const temp_count =
arraysize(temps);
1825 call_descriptor->ParameterCount())),
1826 0,
nullptr, 0,
nullptr, temp_count, temps);
1829 for (
size_t n = 0; n < arguments->size(); ++
n) {
1831 if (input.node.valid()) {
1832 int const slot =
static_cast<int>(
n);
1835 InstructionOperand value = g.CanBeImmediate(node)
1836 ? g.UseImmediate(input.node)
1837 : g.UseRegister(input.node);
1844 int stack_decrement = 0;
1849 if (!input.node.valid())
continue;
1850 InstructionOperand decrement = g.UseImmediate(stack_decrement);
1851 stack_decrement = 0;
1852 if (g.CanBeImmediate(input.node)) {
1853 Emit(kIA32Push, g.NoOutput(), decrement, g.UseImmediate(input.node));
1858 Emit(kIA32Push, g.NoOutput(), decrement, g.UseRegister(input.node));
1859 }
else if (g.CanBeMemoryOperand(kIA32Push, node, input.node,
1861 InstructionOperand outputs[1];
1862 InstructionOperand
inputs[5];
1866 input.node,
inputs, &input_count);
1871 Emit(kIA32Push, g.NoOutput(), decrement, g.UseAny(input.node));
1879 ZoneVector<PushParameter>* results,
const CallDescriptor* call_descriptor,
1882 IA32OperandGeneratorT g(
this);
1885 if (!output.location.IsCallerFrameSlot())
continue;
1887 if (output.node.valid()) {
1888 DCHECK(!call_descriptor->IsCFunctionCall());
1896 int offset = call_descriptor->GetOffsetToReturns();
1897 int reverse_slot = -output.location.GetLocation() -
offset;
1898 Emit(kIA32Peek, g.DefineAsRegister(output.node),
1899 g.UseImmediate(reverse_slot));
1909void VisitCompareWithMemoryOperand(InstructionSelectorT* selector,
1911 InstructionOperand right,
1912 FlagsContinuationT* cont) {
1913 DCHECK(selector->IsLoadOrLoadImmutable(left));
1914 IA32OperandGeneratorT g(selector);
1916 InstructionOperand inputs[4];
1918 g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
1922 selector->EmitWithContinuation(opcode, 0,
nullptr, input_count, inputs, cont);
1927 InstructionOperand left, InstructionOperand right,
1928 FlagsContinuationT* cont) {
1929 selector->EmitWithContinuation(opcode, left, right, cont);
1936 IA32OperandGeneratorT g(selector);
1937 if (commutative && g.CanBeBetterLeftOperand(right)) {
1938 std::swap(left, right);
1940 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
1943MachineType MachineTypeForNarrow(InstructionSelectorT* selector,
OpIndex node,
1945 if (selector->IsLoadOrLoadImmutable(hint_node)) {
1946 MachineType hint = selector->load_view(hint_node).loaded_rep();
1947 if (int64_t constant;
1948 selector->MatchSignedIntegralConstant(node, &constant)) {
1950 if (constant >= std::numeric_limits<int8_t>::min() &&
1951 constant <= std::numeric_limits<int8_t>::max()) {
1955 if (constant >= std::numeric_limits<uint8_t>::min() &&
1956 constant <= std::numeric_limits<uint8_t>::max()) {
1960 if (constant >= std::numeric_limits<int16_t>::min() &&
1961 constant <= std::numeric_limits<int16_t>::max()) {
1965 if (constant >= std::numeric_limits<uint16_t>::min() &&
1966 constant <= std::numeric_limits<uint16_t>::max()) {
1972 if (constant >= 0)
return hint;
1976 return selector->IsLoadOrLoadImmutable(node)
1977 ? selector->load_view(node).loaded_rep()
1985 OpIndex right, FlagsContinuationT* cont) {
1989 MachineType left_type = MachineTypeForNarrow(selector, left, right);
1990 MachineType right_type = MachineTypeForNarrow(selector, right, left);
1991 if (left_type == right_type) {
1992 switch (left_type.representation()) {
1995 if (opcode == kIA32Test)
return kIA32Test8;
1996 if (opcode == kIA32Cmp) {
1998 cont->OverwriteUnsignedIfSigned();
2007 if (opcode == kIA32Test)
return kIA32Test16;
2008 if (opcode == kIA32Cmp) {
2010 cont->OverwriteUnsignedIfSigned();
2026 FlagsContinuationT* cont) {
2027 auto left = selector->input_at(node, 0);
2028 auto right = selector->input_at(node, 1);
2029 VisitCompare(selector, kIA32Float32Cmp, right, left, cont,
false);
2034 FlagsContinuationT* cont) {
2035 auto left = selector->input_at(node, 0);
2036 auto right = selector->input_at(node, 1);
2037 VisitCompare(selector, kIA32Float64Cmp, right, left, cont,
false);
2044 IA32OperandGeneratorT g(selector);
2045 auto left = selector->input_at(node, 0);
2046 auto right = selector->input_at(node, 1);
2049 TryNarrowOpcodeSize(selector, opcode, left, right, cont);
2051 int effect_level = selector->GetEffectLevel(node, cont);
2055 if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) ||
2056 (g.CanBeMemoryOperand(narrowed_opcode, node, right, effect_level) &&
2057 !g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level))) {
2058 if (!selector->IsCommutative(node)) cont->Commute();
2059 std::swap(left, right);
2063 if (g.CanBeImmediate(right)) {
2064 if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) {
2065 return VisitCompareWithMemoryOperand(selector, narrowed_opcode, left,
2066 g.UseImmediate(right), cont);
2068 return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
2073 if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) {
2074 bool needs_byte_register =
2075 narrowed_opcode == kIA32Test8 || narrowed_opcode == kIA32Cmp8;
2076 return VisitCompareWithMemoryOperand(
2077 selector, narrowed_opcode, left,
2078 needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right),
2082 return VisitCompare(selector, opcode, left, right, cont,
2083 selector->IsCommutative(node));
2088 FlagsContinuationT* cont) {
2092void VisitAtomicBinOp(InstructionSelectorT* selector,
OpIndex node,
2095 IA32OperandGeneratorT g(selector);
2097 OpIndex index = selector->input_at(node, 1);
2098 OpIndex value = selector->input_at(node, 2);
2099 InstructionOperand inputs[] = {
2100 g.UseUniqueRegister(value), g.UseUniqueRegister(base),
2101 g.GetEffectiveIndexOperand(index, &addressing_mode)};
2102 InstructionOperand outputs[] = {g.DefineAsFixed(node, eax)};
2104 ? g.UseByteRegister(node)
2105 : g.TempRegister()};
2111void VisitPairAtomicBinOp(InstructionSelectorT* selector,
OpIndex node,
2113 IA32OperandGeneratorT g(selector);
2115 OpIndex index = selector->input_at(node, 1);
2116 OpIndex value = selector->input_at(node, 2);
2119 OpIndex value_high = selector->input_at(node, 3);
2124 InstructionOperand inputs[] = {
2125 g.UseUniqueRegisterOrSlotOrConstant(value), g.UseFixed(value_high, ecx),
2126 g.UseUniqueRegister(base),
2127 g.GetEffectiveIndexOperand(index, &addressing_mode)};
2131 InstructionOperand outputs[2];
2132 size_t output_count = 0;
2133 InstructionOperand temps[2];
2134 size_t temp_count = 0;
2135 if (projection0.valid()) {
2136 outputs[output_count++] = g.DefineAsFixed(projection0.value(), eax);
2138 temps[temp_count++] = g.TempRegister(eax);
2140 if (projection1.valid()) {
2141 outputs[output_count++] = g.DefineAsFixed(projection1.value(), edx);
2143 temps[temp_count++] = g.TempRegister(edx);
2145 selector->Emit(code, output_count, outputs,
arraysize(inputs), inputs,
2153 FlagsContinuation* cont) {
2159 if (
const ComparisonOp* comparison = value_op.TryCast<ComparisonOp>()) {
2160 switch (comparison->rep.MapTaggedToWord().value()) {
2162 cont->OverwriteAndNegateIfEqual(
2167 case ComparisonOp::Kind::kEqual:
2168 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
2170 case ComparisonOp::Kind::kSignedLessThan:
2171 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
2173 case ComparisonOp::Kind::kSignedLessThanOrEqual:
2174 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
2179 case RegisterRepresentation::Float64():
2181 case ComparisonOp::Kind::kEqual:
2182 cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
2184 case ComparisonOp::Kind::kSignedLessThan:
2185 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
2187 case ComparisonOp::Kind::kSignedLessThanOrEqual:
2188 cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
2196 }
else if (value_op.Is<Opmask::kWord32Sub>()) {
2198 }
else if (value_op.Is<Opmask::kWord32BitwiseAnd>()) {
2200 }
else if (
const ProjectionOp* projection =
2201 value_op.TryCast<ProjectionOp>()) {
2204 if (projection->index == 1u) {
2210 OpIndex node = projection->input();
2211 if (
const OverflowCheckedBinopOp* binop =
2212 this->TryCast<OverflowCheckedBinopOp>(node);
2213 binop && CanDoBranchIfOverflowFusion(node)) {
2214 DCHECK_EQ(binop->rep, WordRepresentation::Word32());
2215 cont->OverwriteAndNegateIfEqual(kOverflow);
2216 switch (binop->kind) {
2217 case OverflowCheckedBinopOp::Kind::kSignedAdd:
2218 return VisitBinop(
this, node, kIA32Add, cont);
2219 case OverflowCheckedBinopOp::Kind::kSignedSub:
2220 return VisitBinop(
this, node, kIA32Sub, cont);
2221 case OverflowCheckedBinopOp::Kind::kSignedMul:
2222 return VisitBinop(
this, node, kIA32Imul, cont);
2227 }
else if (value_op.Is<StackPointerGreaterThanOp>()) {
2228 cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
2229 return VisitStackPointerGreaterThan(value, cont);
2234 IA32OperandGeneratorT g(
this);
2235 VisitCompare(
this, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
2238void InstructionSelectorT::VisitSwitch(OpIndex node,
const SwitchInfo& sw) {
2240 IA32OperandGeneratorT g(
this);
2241 InstructionOperand value_operand = g.UseRegister(this->input_at(node, 0));
2244 if (enable_switch_jump_table_ ==
2245 InstructionSelector::kEnableSwitchJumpTable) {
2246 static const size_t kMaxTableSwitchValueRange = 2 << 16;
2247 size_t table_space_cost = 4 + sw.value_range();
2248 size_t table_time_cost = 3;
2249 size_t lookup_space_cost = 3 + 2 * sw.case_count();
2250 size_t lookup_time_cost = sw.case_count();
2251 if (sw.case_count() > 4 &&
2252 table_space_cost + 3 * table_time_cost <=
2253 lookup_space_cost + 3 * lookup_time_cost &&
2254 sw.min_value() > std::numeric_limits<int32_t>::min() &&
2255 sw.value_range() <= kMaxTableSwitchValueRange) {
2256 InstructionOperand index_operand = value_operand;
2257 if (sw.min_value()) {
2258 index_operand = g.TempRegister();
2259 Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
2260 value_operand, g.TempImmediate(-sw.min_value()));
2263 return EmitTableSwitch(sw, index_operand);
2268 return EmitBinarySearchSwitch(sw, value_operand);
2272void InstructionSelectorT::VisitWord32Equal(OpIndex node) {
2273 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
2274 const ComparisonOp& comparison =
2275 this->
Get(node).template Cast<ComparisonOp>();
2276 if (this->MatchIntegralZero(comparison.right())) {
2277 return VisitWordCompareZero(node, comparison.left(), &cont);
2282void InstructionSelectorT::VisitInt32LessThan(OpIndex node) {
2283 FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
2287void InstructionSelectorT::VisitInt32LessThanOrEqual(OpIndex node) {
2288 FlagsContinuation cont =
2289 FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
2293void InstructionSelectorT::VisitUint32LessThan(OpIndex node) {
2294 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
2298void InstructionSelectorT::VisitUint32LessThanOrEqual(OpIndex node) {
2299 FlagsContinuation cont =
2300 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
2304void InstructionSelectorT::VisitInt32AddWithOverflow(OpIndex node) {
2307 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf.value());
2308 return VisitBinop(
this, node, kIA32Add, &cont);
2310 FlagsContinuation cont;
2311 VisitBinop(
this, node, kIA32Add, &cont);
2314void InstructionSelectorT::VisitInt32SubWithOverflow(OpIndex node) {
2317 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf.value());
2318 return VisitBinop(
this, node, kIA32Sub, &cont);
2320 FlagsContinuation cont;
2321 VisitBinop(
this, node, kIA32Sub, &cont);
2324void InstructionSelectorT::VisitInt32MulWithOverflow(OpIndex node) {
2327 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf.value());
2328 return VisitBinop(
this, node, kIA32Imul, &cont);
2330 FlagsContinuation cont;
2331 VisitBinop(
this, node, kIA32Imul, &cont);
2334void InstructionSelectorT::VisitFloat32Equal(OpIndex node) {
2335 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
2339void InstructionSelectorT::VisitFloat32LessThan(OpIndex node) {
2340 FlagsContinuation cont =
2341 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
2345void InstructionSelectorT::VisitFloat32LessThanOrEqual(OpIndex node) {
2346 FlagsContinuation cont =
2347 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
2351void InstructionSelectorT::VisitFloat64Equal(OpIndex node) {
2352 FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node);
2356void InstructionSelectorT::VisitFloat64LessThan(OpIndex node) {
2357 FlagsContinuation cont =
2358 FlagsContinuation::ForSet(kUnsignedGreaterThan, node);
2362void InstructionSelectorT::VisitFloat64LessThanOrEqual(OpIndex node) {
2363 FlagsContinuation cont =
2364 FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node);
2368void InstructionSelectorT::VisitFloat64InsertLowWord32(OpIndex node) {
2373void InstructionSelectorT::VisitFloat64InsertHighWord32(OpIndex node) {
2378void InstructionSelectorT::VisitBitcastWord32PairToFloat64(OpIndex node) {
2379 IA32OperandGeneratorT g(
this);
2380 const BitcastWord32PairToFloat64Op& cast_op =
2381 this->
Get(node).template Cast<BitcastWord32PairToFloat64Op>();
2382 Emit(kIA32Float64FromWord32Pair, g.DefineAsRegister(node),
2383 g.Use(cast_op.low_word32()), g.Use(cast_op.high_word32()));
2386void InstructionSelectorT::VisitFloat64SilenceNaN(OpIndex node) {
2387 IA32OperandGeneratorT g(
this);
2388 Emit(kIA32Float64SilenceNaN, g.DefineSameAsFirst(node),
2389 g.UseRegister(this->input_at(node, 0)));
2397 return AtomicMemoryOrder::kSeqCst;
2400 return barrier->memory_order;
2405void InstructionSelectorT::VisitMemoryBarrier(
OpIndex node) {
2409 if (order == AtomicMemoryOrder::kSeqCst) {
2410 IA32OperandGeneratorT g(
this);
2411 Emit(kIA32MFence, g.NoOutput());
2414 DCHECK_EQ(AtomicMemoryOrder::kAcqRel, order);
2417void InstructionSelectorT::VisitWord32AtomicLoad(OpIndex node) {
2418 LoadRepresentation load_rep = this->load_view(node).loaded_rep();
2419 DCHECK(load_rep.representation() == MachineRepresentation::kWord8 ||
2420 load_rep.representation() == MachineRepresentation::kWord16 ||
2421 load_rep.representation() == MachineRepresentation::kWord32 ||
2422 load_rep.representation() == MachineRepresentation::kTaggedSigned ||
2423 load_rep.representation() == MachineRepresentation::kTaggedPointer ||
2424 load_rep.representation() == MachineRepresentation::kTagged);
2428 VisitLoad(node, node, GetLoadOpcode(load_rep));
2431void InstructionSelectorT::VisitWord32AtomicStore(OpIndex node) {
2437 selector->
Get(node).template Cast<AtomicRMWOp>();
2441void InstructionSelectorT::VisitWord32AtomicExchange(
OpIndex node) {
2442 IA32OperandGeneratorT g(
this);
2445 if (type == MachineType::Int8()) {
2446 opcode = kAtomicExchangeInt8;
2447 }
else if (type == MachineType::Uint8()) {
2448 opcode = kAtomicExchangeUint8;
2449 }
else if (type == MachineType::Int16()) {
2450 opcode = kAtomicExchangeInt16;
2451 }
else if (type == MachineType::Uint16()) {
2452 opcode = kAtomicExchangeUint16;
2453 }
else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2454 opcode = kAtomicExchangeWord32;
2461void InstructionSelectorT::VisitWord32AtomicCompareExchange(OpIndex node) {
2462 IA32OperandGeneratorT g(
this);
2463 const AtomicRMWOp& atomic_op = Cast<AtomicRMWOp>(node);
2465 OpIndex index = atomic_op.index();
2466 OpIndex old_value = atomic_op.expected().value();
2467 OpIndex new_value = atomic_op.value();
2471 if (type == MachineType::Int8()) {
2472 opcode = kAtomicCompareExchangeInt8;
2473 }
else if (type == MachineType::Uint8()) {
2474 opcode = kAtomicCompareExchangeUint8;
2475 }
else if (type == MachineType::Int16()) {
2476 opcode = kAtomicCompareExchangeInt16;
2477 }
else if (type == MachineType::Uint16()) {
2478 opcode = kAtomicCompareExchangeUint16;
2479 }
else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2480 opcode = kAtomicCompareExchangeWord32;
2485 InstructionOperand new_val_operand =
2486 (type.representation() == MachineRepresentation::kWord8)
2487 ? g.UseByteRegister(new_value)
2488 : g.UseUniqueRegister(new_value);
2489 InstructionOperand inputs[] = {
2490 g.UseFixed(old_value, eax), new_val_operand, g.UseUniqueRegister(
base),
2491 g.GetEffectiveIndexOperand(index, &addressing_mode)};
2492 InstructionOperand outputs[] = {g.DefineAsFixed(node, eax)};
2493 InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
2494 Emit(code, 1, outputs,
arraysize(inputs), inputs);
2497void InstructionSelectorT::VisitWord32AtomicBinaryOperation(
2498 OpIndex node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
2499 ArchOpcode uint16_op, ArchOpcode word32_op) {
2503 if (type == MachineType::Int8()) {
2505 }
else if (type == MachineType::Uint8()) {
2507 }
else if (type == MachineType::Int16()) {
2509 }
else if (type == MachineType::Uint16()) {
2511 }
else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
2516 VisitAtomicBinOp(
this, node, opcode, type.representation());
2520#define VISIT_ATOMIC_BINOP(op) \
2521 void InstructionSelectorT::VisitWord32Atomic##op(OpIndex node) { \
2522 VisitWord32AtomicBinaryOperation( \
2523 node, kAtomic##op##Int8, kAtomic##op##Uint8, kAtomic##op##Int16, \
2524 kAtomic##op##Uint16, kAtomic##op##Word32); \
2531#undef VISIT_ATOMIC_BINOP
2533void InstructionSelectorT::VisitWord32AtomicPairLoad(OpIndex node) {
2536 IA32OperandGeneratorT g(
this);
2537 AddressingMode
mode;
2538 OpIndex
base = this->input_at(node, 0);
2539 OpIndex index = this->input_at(node, 1);
2540 OptionalOpIndex projection0 = FindProjection(node, 0);
2541 OptionalOpIndex projection1 = FindProjection(node, 1);
2542 if (projection0.valid() && projection1.valid()) {
2543 InstructionOperand inputs[] = {g.UseUniqueRegister(
base),
2544 g.GetEffectiveIndexOperand(index, &mode)};
2545 InstructionCode code =
2546 kIA32Word32AtomicPairLoad | AddressingModeField::encode(mode);
2547 InstructionOperand outputs[] = {g.DefineAsRegister(projection0.value()),
2548 g.DefineAsRegister(projection1.value())};
2549 Emit(code, 2, outputs, 2, inputs);
2550 }
else if (projection0.valid() || projection1.valid()) {
2552 ArchOpcode opcode = kIA32Movl;
2554 InstructionOperand outputs[] = {g.DefineAsRegister(
2555 projection0.valid() ? projection0.value() : projection1.value())};
2556 InstructionOperand inputs[3];
2557 size_t input_count = 0;
2561 mode = g.GenerateMemoryOperandInputs(
2562 index,
scale,
base, projection0.valid() ? 0 : 4, kPositiveDisplacement,
2563 inputs, &input_count);
2564 InstructionCode code = opcode | AddressingModeField::encode(mode);
2565 Emit(code, 1, outputs, input_count, inputs);
2569void InstructionSelectorT::VisitWord32AtomicPairStore(OpIndex node) {
2574 IA32OperandGeneratorT g(
this);
2576 OpIndex index = this->input_at(node, 1);
2577 OpIndex value = this->input_at(node, 2);
2578 OpIndex value_high = this->input_at(node, 3);
2581 if (order == AtomicMemoryOrder::kAcqRel) {
2583 InstructionOperand inputs[] = {
2584 g.UseUniqueRegisterOrSlotOrConstant(value),
2585 g.UseUniqueRegisterOrSlotOrConstant(value_high),
2586 g.UseUniqueRegister(
base),
2587 g.GetEffectiveIndexOperand(index, &addressing_mode),
2590 AddressingModeField::encode(addressing_mode);
2591 Emit(code, 0,
nullptr,
arraysize(inputs), inputs);
2593 DCHECK_EQ(order, AtomicMemoryOrder::kSeqCst);
2596 InstructionOperand inputs[] = {
2597 g.UseUniqueRegisterOrSlotOrConstant(value), g.UseFixed(value_high, ecx),
2598 g.UseUniqueRegister(
base),
2599 g.GetEffectiveIndexOperand(index, &addressing_mode)};
2603 InstructionOperand temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
2606 AddressingModeField::encode(addressing_mode);
2607 Emit(code, 0,
nullptr,
arraysize(inputs), inputs, num_temps, temps);
2611void InstructionSelectorT::VisitWord32AtomicPairAdd(OpIndex node) {
2612 VisitPairAtomicBinOp(
this, node, kIA32Word32AtomicPairAdd);
2615void InstructionSelectorT::VisitWord32AtomicPairSub(OpIndex node) {
2616 VisitPairAtomicBinOp(
this, node, kIA32Word32AtomicPairSub);
2619void InstructionSelectorT::VisitWord32AtomicPairAnd(OpIndex node) {
2620 VisitPairAtomicBinOp(
this, node, kIA32Word32AtomicPairAnd);
2623void InstructionSelectorT::VisitWord32AtomicPairOr(OpIndex node) {
2624 VisitPairAtomicBinOp(
this, node, kIA32Word32AtomicPairOr);
2627void InstructionSelectorT::VisitWord32AtomicPairXor(OpIndex node) {
2628 VisitPairAtomicBinOp(
this, node, kIA32Word32AtomicPairXor);
2631void InstructionSelectorT::VisitWord32AtomicPairExchange(OpIndex node) {
2632 VisitPairAtomicBinOp(
this, node, kIA32Word32AtomicPairExchange);
2635void InstructionSelectorT::VisitWord32AtomicPairCompareExchange(OpIndex node) {
2636 IA32OperandGeneratorT g(
this);
2637 OpIndex index = this->input_at(node, 1);
2640 const size_t expected_offset = 4;
2641 const size_t value_offset = 2;
2642 InstructionOperand inputs[] = {
2644 g.UseFixed(this->input_at(node, expected_offset), eax),
2645 g.UseFixed(this->input_at(node, expected_offset + 1), edx),
2647 g.UseUniqueRegisterOrSlotOrConstant(this->input_at(node, value_offset)),
2648 g.UseFixed(this->input_at(node, value_offset + 1), ecx),
2650 g.UseUniqueRegister(this->input_at(node, 0)),
2651 g.GetEffectiveIndexOperand(index, &addressing_mode)};
2655 AddressingModeField::encode(addressing_mode);
2657 InstructionOperand outputs[2];
2658 size_t output_count = 0;
2659 InstructionOperand temps[2];
2660 size_t temp_count = 0;
2661 if (projection0.valid()) {
2662 outputs[output_count++] = g.DefineAsFixed(projection0.value(), eax);
2664 temps[temp_count++] = g.TempRegister(eax);
2666 if (projection1.valid()) {
2667 outputs[output_count++] = g.DefineAsFixed(projection1.value(), edx);
2669 temps[temp_count++] = g.TempRegister(edx);
2671 Emit(code, output_count, outputs,
arraysize(inputs), inputs, temp_count,
2675#define SIMD_INT_TYPES(V) \
2680#define SIMD_BINOP_LIST(V) \
2692#define SIMD_BINOP_UNIFIED_SSE_AVX_LIST(V) \
2703 IF_WASM(V, F64x2Add) \
2704 IF_WASM(V, F64x2Sub) \
2705 IF_WASM(V, F64x2Mul) \
2706 IF_WASM(V, F64x2Div) \
2707 IF_WASM(V, F64x2Eq) \
2708 IF_WASM(V, F64x2Ne) \
2709 IF_WASM(V, F64x2Lt) \
2710 IF_WASM(V, F64x2Le) \
2740 V(I16x8SConvertI32x4) \
2741 V(I16x8UConvertI32x4) \
2742 V(I16x8RoundingAverageU) \
2755 V(I8x16SConvertI16x8) \
2756 V(I8x16UConvertI16x8) \
2757 V(I8x16RoundingAverageU) \
2764#define SIMD_BINOP_RRR(V) \
2765 V(I64x2ExtMulLowI32x4S) \
2766 V(I64x2ExtMulHighI32x4S) \
2767 V(I64x2ExtMulLowI32x4U) \
2768 V(I64x2ExtMulHighI32x4U) \
2769 V(I32x4ExtMulLowI16x8S) \
2770 V(I32x4ExtMulHighI16x8S) \
2771 V(I32x4ExtMulLowI16x8U) \
2772 V(I32x4ExtMulHighI16x8U) \
2773 V(I16x8ExtMulLowI8x16S) \
2774 V(I16x8ExtMulHighI8x16S) \
2775 V(I16x8ExtMulLowI8x16U) \
2776 V(I16x8ExtMulHighI8x16U) \
2777 V(I16x8Q15MulRSatS) \
2778 V(I16x8RelaxedQ15MulRS)
2780#define SIMD_UNOP_LIST(V) \
2781 V(F64x2ConvertLowI32x4S) \
2782 V(F32x4DemoteF64x2Zero) \
2784 V(F32x4SConvertI32x4) \
2786 V(I64x2SConvertI32x4Low) \
2787 V(I64x2SConvertI32x4High) \
2788 V(I64x2UConvertI32x4Low) \
2789 V(I64x2UConvertI32x4High) \
2790 V(I32x4SConvertI16x8Low) \
2791 V(I32x4SConvertI16x8High) \
2793 V(I32x4UConvertI16x8Low) \
2794 V(I32x4UConvertI16x8High) \
2797 V(I16x8SConvertI8x16Low) \
2798 V(I16x8SConvertI8x16High) \
2800 V(I16x8UConvertI8x16Low) \
2801 V(I16x8UConvertI8x16High) \
2808#define SIMD_ALLTRUE_LIST(V) \
2814#define SIMD_SHIFT_OPCODES_UNIFED_SSE_AVX(V) \
2824#if V8_ENABLE_WEBASSEMBLY
2826void InstructionSelectorT::VisitS128Const(OpIndex node) {
2827 IA32OperandGeneratorT g(
this);
2828 static const int kUint32Immediates = kSimd128Size /
sizeof(uint32_t);
2829 uint32_t val[kUint32Immediates];
2830 const Simd128ConstantOp& constant =
2831 this->Get(node).template Cast<Simd128ConstantOp>();
2832 memcpy(val, constant.value, kSimd128Size);
2834 bool all_zeros = !(val[0] || val[1] || val[2] || val[3]);
2835 bool all_ones = val[0] == UINT32_MAX && val[1] == UINT32_MAX &&
2836 val[2] == UINT32_MAX && val[3] == UINT32_MAX;
2837 InstructionOperand dst = g.DefineAsRegister(node);
2839 Emit(kIA32S128Zero, dst);
2840 }
else if (all_ones) {
2841 Emit(kIA32S128AllOnes, dst);
2843 InstructionOperand inputs[kUint32Immediates];
2844 for (
int i = 0;
i < kUint32Immediates; ++
i) {
2845 inputs[
i] = g.UseImmediate(val[
i]);
2847 InstructionOperand temp(g.TempRegister());
2848 Emit(kIA32S128Const, 1, &dst, kUint32Immediates, inputs, 1, &temp);
2852void InstructionSelectorT::VisitF64x2Min(OpIndex node) {
2853 IA32OperandGeneratorT g(
this);
2854 InstructionOperand operand0 = g.UseRegister(this->input_at(node, 0));
2855 InstructionOperand operand1 = g.UseRegister(this->input_at(node, 1));
2857 if (IsSupported(AVX)) {
2858 Emit(kIA32F64x2Min, g.DefineAsRegister(node), operand0, operand1);
2860 Emit(kIA32F64x2Min, g.DefineSameAsFirst(node), operand0, operand1);
2864void InstructionSelectorT::VisitF64x2Max(OpIndex node) {
2865 IA32OperandGeneratorT g(
this);
2866 InstructionOperand operand0 = g.UseRegister(this->input_at(node, 0));
2867 InstructionOperand operand1 = g.UseRegister(this->input_at(node, 1));
2868 if (IsSupported(AVX)) {
2869 Emit(kIA32F64x2Max, g.DefineAsRegister(node), operand0, operand1);
2871 Emit(kIA32F64x2Max, g.DefineSameAsFirst(node), operand0, operand1);
2875void InstructionSelectorT::VisitF64x2Splat(OpIndex node) {
2876 VisitRRSimd(
this, node, kIA32F64x2Splat);
2879void InstructionSelectorT::VisitF64x2ExtractLane(OpIndex node) {
2880 VisitRRISimd(
this, node, kIA32F64x2ExtractLane, kIA32F64x2ExtractLane);
2883void InstructionSelectorT::VisitI64x2SplatI32Pair(OpIndex node) {
2888void InstructionSelectorT::VisitI64x2ReplaceLaneI32Pair(OpIndex node) {
2893void InstructionSelectorT::VisitI64x2Neg(OpIndex node) {
2894 IA32OperandGeneratorT g(
this);
2896 InstructionOperand operand0 =
2897 IsSupported(AVX) ? g.UseRegister(this->input_at(node, 0))
2898 : g.UseUniqueRegister(this->input_at(node, 0));
2899 Emit(kIA32I64x2Neg, g.DefineAsRegister(node), operand0);
2902void InstructionSelectorT::VisitI64x2ShrS(OpIndex node) {
2903 IA32OperandGeneratorT g(
this);
2904 InstructionOperand dst =
2905 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
2907 if (g.CanBeImmediate(this->input_at(node, 1))) {
2908 Emit(kIA32I64x2ShrS, dst, g.UseRegister(this->input_at(node, 0)),
2909 g.UseImmediate(this->input_at(node, 1)));
2911 InstructionOperand temps[] = {g.TempSimd128Register(), g.TempRegister()};
2912 Emit(kIA32I64x2ShrS, dst, g.UseUniqueRegister(this->input_at(node, 0)),
2913 g.UseRegister(this->input_at(node, 1)),
arraysize(temps), temps);
2917void InstructionSelectorT::VisitI64x2Mul(OpIndex node) {
2918 IA32OperandGeneratorT g(
this);
2919 InstructionOperand temps[] = {g.TempSimd128Register(),
2920 g.TempSimd128Register()};
2921 Emit(kIA32I64x2Mul, g.DefineAsRegister(node),
2922 g.UseUniqueRegister(this->input_at(node, 0)),
2923 g.UseUniqueRegister(this->input_at(node, 1)),
arraysize(temps), temps);
2926void InstructionSelectorT::VisitF32x4Splat(OpIndex node) {
2927 VisitRRSimd(
this, node, kIA32F32x4Splat);
2930void InstructionSelectorT::VisitF32x4ExtractLane(OpIndex node) {
2931 VisitRRISimd(
this, node, kIA32F32x4ExtractLane);
2934void InstructionSelectorT::VisitF32x4UConvertI32x4(OpIndex node) {
2935 VisitRRSimd(
this, node, kIA32F32x4UConvertI32x4);
2938void InstructionSelectorT::VisitI32x4SConvertF32x4(OpIndex node) {
2939 IA32OperandGeneratorT g(
this);
2940 InstructionOperand temps[] = {g.TempRegister()};
2941 InstructionOperand dst =
2942 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
2943 Emit(kIA32I32x4SConvertF32x4, dst, g.UseRegister(this->input_at(node, 0)),
2947void InstructionSelectorT::VisitI32x4UConvertF32x4(OpIndex node) {
2948 IA32OperandGeneratorT g(
this);
2949 InstructionOperand temps[] = {g.TempSimd128Register(),
2950 g.TempSimd128Register()};
2952 IsSupported(AVX) ? kAVXI32x4UConvertF32x4 : kSSEI32x4UConvertF32x4;
2953 Emit(opcode, g.DefineSameAsFirst(node),
2954 g.UseRegister(this->input_at(node, 0)),
arraysize(temps), temps);
2957void InstructionSelectorT::VisitS128Zero(OpIndex node) {
2958 IA32OperandGeneratorT g(
this);
2959 Emit(kIA32S128Zero, g.DefineAsRegister(node));
2962void InstructionSelectorT::VisitS128Select(OpIndex node) {
2963 IA32OperandGeneratorT g(
this);
2964 InstructionOperand dst =
2965 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
2966 Emit(kIA32S128Select, dst, g.UseRegister(this->input_at(node, 0)),
2967 g.UseRegister(this->input_at(node, 1)),
2968 g.UseRegister(this->input_at(node, 2)));
2971void InstructionSelectorT::VisitS128AndNot(OpIndex node) {
2972 IA32OperandGeneratorT g(
this);
2974 InstructionOperand dst =
2975 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
2976 Emit(kIA32S128AndNot, dst, g.UseRegister(this->input_at(node, 1)),
2977 g.UseRegister(this->input_at(node, 0)));
2980#define VISIT_SIMD_SPLAT(Type) \
2981 void InstructionSelectorT::Visit##Type##Splat(OpIndex node) { \
2982 bool set_zero = this->MatchIntegralZero(this->input_at(node, 0)); \
2984 IA32OperandGeneratorT g(this); \
2985 Emit(kIA32S128Zero, g.DefineAsRegister(node)); \
2987 VisitRO(this, node, kIA32##Type##Splat); \
2991#undef SIMD_INT_TYPES
2992#undef VISIT_SIMD_SPLAT
2994void InstructionSelectorT::VisitF16x8Splat(OpIndex node) {
UNIMPLEMENTED(); }
2996void InstructionSelectorT::VisitI8x16ExtractLaneU(OpIndex node) {
2997 VisitRRISimd(
this, node, kIA32Pextrb);
3000void InstructionSelectorT::VisitI8x16ExtractLaneS(OpIndex node) {
3001 VisitRRISimd(
this, node, kIA32I8x16ExtractLaneS);
3004void InstructionSelectorT::VisitI16x8ExtractLaneU(OpIndex node) {
3005 VisitRRISimd(
this, node, kIA32Pextrw);
3008void InstructionSelectorT::VisitI16x8ExtractLaneS(OpIndex node) {
3009 VisitRRISimd(
this, node, kIA32I16x8ExtractLaneS);
3012void InstructionSelectorT::VisitI32x4ExtractLane(OpIndex node) {
3013 VisitRRISimd(
this, node, kIA32I32x4ExtractLane);
3016void InstructionSelectorT::VisitF16x8ExtractLane(OpIndex node) {
3020void InstructionSelectorT::VisitF16x8ReplaceLane(OpIndex node) {
3024#define SIMD_REPLACE_LANE_TYPE_OP(V) \
3025 V(I32x4, kIA32Pinsrd) \
3026 V(I16x8, kIA32Pinsrw) \
3027 V(I8x16, kIA32Pinsrb) \
3028 V(F32x4, kIA32Insertps) \
3029 V(F64x2, kIA32F64x2ReplaceLane)
3031#define VISIT_SIMD_REPLACE_LANE(TYPE, OPCODE) \
3032 void InstructionSelectorT::Visit##TYPE##ReplaceLane(OpIndex node) { \
3033 IA32OperandGeneratorT g(this); \
3034 const Simd128ReplaceLaneOp& op = \
3035 this->Get(node).template Cast<Simd128ReplaceLaneOp>(); \
3036 int lane = op.lane; \
3037 InstructionOperand operand0 = g.UseRegister(this->input_at(node, 0)); \
3038 InstructionOperand operand1 = g.UseImmediate(lane); \
3039 auto input1 = this->input_at(node, 1); \
3040 InstructionOperand operand2; \
3041 if constexpr (OPCODE == kIA32F64x2ReplaceLane) { \
3042 operand2 = g.UseRegister(input1); \
3044 operand2 = g.Use(input1); \
3047 InstructionOperand dst = IsSupported(AVX) ? g.DefineAsRegister(node) \
3048 : g.DefineSameAsFirst(node); \
3049 Emit(OPCODE, dst, operand0, operand1, operand2); \
3051SIMD_REPLACE_LANE_TYPE_OP(VISIT_SIMD_REPLACE_LANE)
3052#undef VISIT_SIMD_REPLACE_LANE
3053#undef SIMD_REPLACE_LANE_TYPE_OP
3055#define VISIT_SIMD_SHIFT_UNIFIED_SSE_AVX(Opcode) \
3056 void InstructionSelectorT::Visit##Opcode(OpIndex node) { \
3057 VisitRROSimdShift(this, node, kIA32##Opcode); \
3060#undef VISIT_SIMD_SHIFT_UNIFIED_SSE_AVX
3061#undef SIMD_SHIFT_OPCODES_UNIFED_SSE_AVX
3067#define VISIT_SIMD_UNOP(Opcode) \
3068 void InstructionSelectorT::Visit##Opcode(OpIndex node) { \
3069 IA32OperandGeneratorT g(this); \
3070 Emit(kIA32##Opcode, g.DefineAsRegister(node), \
3071 g.UseRegister(this->input_at(node, 0))); \
3074#undef VISIT_SIMD_UNOP
3075#undef SIMD_UNOP_LIST
3077#define UNIMPLEMENTED_SIMD_UNOP_LIST(V) \
3086#define SIMD_VISIT_UNIMPL_UNOP(Name) \
3087 void InstructionSelectorT::Visit##Name(OpIndex node) { UNIMPLEMENTED(); }
3089UNIMPLEMENTED_SIMD_UNOP_LIST(SIMD_VISIT_UNIMPL_UNOP)
3090#undef SIMD_VISIT_UNIMPL_UNOP
3091#undef UNIMPLEMENTED_SIMD_UNOP_LIST
3093#define UNIMPLEMENTED_SIMD_CVTOP_LIST(V) \
3094 V(F16x8SConvertI16x8) \
3095 V(F16x8UConvertI16x8) \
3096 V(I16x8SConvertF16x8) \
3097 V(I16x8UConvertF16x8) \
3098 V(F32x4PromoteLowF16x8) \
3099 V(F16x8DemoteF32x4Zero) \
3100 V(F16x8DemoteF64x2Zero)
3102#define SIMD_VISIT_UNIMPL_CVTOP(Name) \
3103 void InstructionSelectorT::Visit##Name(OpIndex node) { UNIMPLEMENTED(); }
3105UNIMPLEMENTED_SIMD_CVTOP_LIST(SIMD_VISIT_UNIMPL_CVTOP)
3106#undef SIMD_VISIT_UNIMPL_CVTOP
3107#undef UNIMPLEMENTED_SIMD_CVTOP_LIST
3109void InstructionSelectorT::VisitV128AnyTrue(OpIndex node) {
3110 IA32OperandGeneratorT g(
this);
3111 InstructionOperand temps[] = {g.TempRegister()};
3112 Emit(kIA32S128AnyTrue, g.DefineAsRegister(node),
3113 g.UseRegister(this->input_at(node, 0)),
arraysize(temps), temps);
3116#define VISIT_SIMD_ALLTRUE(Opcode) \
3117 void InstructionSelectorT::Visit##Opcode(OpIndex node) { \
3118 IA32OperandGeneratorT g(this); \
3119 InstructionOperand temps[] = {g.TempRegister(), g.TempSimd128Register()}; \
3120 Emit(kIA32##Opcode, g.DefineAsRegister(node), \
3121 g.UseUniqueRegister(this->input_at(node, 0)), arraysize(temps), \
3125#undef VISIT_SIMD_ALLTRUE
3126#undef SIMD_ALLTRUE_LIST
3128#define VISIT_SIMD_BINOP(Opcode) \
3129 void InstructionSelectorT::Visit##Opcode(OpIndex node) { \
3130 VisitRROSimd(this, node, kAVX##Opcode, kSSE##Opcode); \
3133#undef VISIT_SIMD_BINOP
3134#undef SIMD_BINOP_LIST
3136#define UNIMPLEMENTED_SIMD_BINOP_LIST(V) \
3150#define SIMD_VISIT_UNIMPL_BINOP(Name) \
3151 void InstructionSelectorT::Visit##Name(OpIndex node) { UNIMPLEMENTED(); }
3153UNIMPLEMENTED_SIMD_BINOP_LIST(SIMD_VISIT_UNIMPL_BINOP)
3154#undef SIMD_VISIT_UNIMPL_BINOP
3155#undef UNIMPLEMENTED_SIMD_BINOP_LIST
3157#define VISIT_SIMD_BINOP_UNIFIED_SSE_AVX(Opcode) \
3158 void InstructionSelectorT::Visit##Opcode(OpIndex node) { \
3159 VisitRROSimd(this, node, kIA32##Opcode, kIA32##Opcode); \
3162#undef VISIT_SIMD_BINOP_UNIFIED_SSE_AVX
3163#undef SIMD_BINOP_UNIFIED_SSE_AVX_LIST
3165#define VISIT_SIMD_BINOP_RRR(OPCODE) \
3166 void InstructionSelectorT::Visit##OPCODE(OpIndex node) { \
3167 VisitRRRSimd(this, node, kIA32##OPCODE); \
3170#undef VISIT_SIMD_BINOP_RRR
3171#undef SIMD_BINOP_RRR
3173void InstructionSelectorT::VisitI16x8BitMask(OpIndex node) {
3174 IA32OperandGeneratorT g(
this);
3175 InstructionOperand temps[] = {g.TempSimd128Register()};
3176 Emit(kIA32I16x8BitMask, g.DefineAsRegister(node),
3177 g.UseUniqueRegister(this->input_at(node, 0)),
arraysize(temps), temps);
3180void InstructionSelectorT::VisitI8x16Shl(OpIndex node) {
3181 VisitI8x16Shift(
this, node, kIA32I8x16Shl);
3184void InstructionSelectorT::VisitI8x16ShrS(OpIndex node) {
3185 VisitI8x16Shift(
this, node, kIA32I8x16ShrS);
3188void InstructionSelectorT::VisitI8x16ShrU(OpIndex node) {
3189 VisitI8x16Shift(
this, node, kIA32I8x16ShrU);
3193void InstructionSelectorT::VisitInt32AbsWithOverflow(OpIndex node) {
3197void InstructionSelectorT::VisitInt64AbsWithOverflow(OpIndex node) {
3201#if V8_ENABLE_WEBASSEMBLY
3207bool TryMatch16x8HalfShuffle(uint8_t* shuffle16x8, uint8_t* blend_mask) {
3209 for (
int i = 0;
i < 8;
i++) {
3210 if ((shuffle16x8[
i] & 0x4) != (
i & 0x4))
return false;
3211 *blend_mask |= (shuffle16x8[
i] > 7 ? 1 : 0) <<
i;
3216struct ShuffleEntry {
3220 bool src0_needs_reg;
3221 bool src1_needs_reg;
3229static const ShuffleEntry arch_shuffles[] = {
3230 {{0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23},
3231 kIA32S64x2UnpackLow,
3232 kIA32S64x2UnpackLow,
3235 {{8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31},
3236 kIA32S64x2UnpackHigh,
3237 kIA32S64x2UnpackHigh,
3240 {{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
3241 kIA32S32x4UnpackLow,
3242 kIA32S32x4UnpackLow,
3245 {{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
3246 kIA32S32x4UnpackHigh,
3247 kIA32S32x4UnpackHigh,
3250 {{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
3251 kIA32S16x8UnpackLow,
3252 kIA32S16x8UnpackLow,
3255 {{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
3256 kIA32S16x8UnpackHigh,
3257 kIA32S16x8UnpackHigh,
3260 {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
3261 kIA32S8x16UnpackLow,
3262 kIA32S8x16UnpackLow,
3265 {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
3266 kIA32S8x16UnpackHigh,
3267 kIA32S8x16UnpackHigh,
3271 {{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
3276 {{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
3281 {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
3286 {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
3292 {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
3293 kSSES8x16TransposeLow,
3294 kAVXS8x16TransposeLow,
3297 {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
3298 kSSES8x16TransposeHigh,
3299 kAVXS8x16TransposeHigh,
3302 {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
3307 {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
3312 {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
3318bool TryMatchArchShuffle(
const uint8_t* shuffle,
const ShuffleEntry* table,
3319 size_t num_entries,
bool is_swizzle,
3320 const ShuffleEntry** arch_shuffle) {
3322 for (
size_t i = 0;
i < num_entries; ++
i) {
3323 const ShuffleEntry& entry = table[
i];
3326 if ((entry.shuffle[j] &
mask) != (shuffle[j] &
mask)) {
3330 if (j == kSimd128Size) {
3331 *arch_shuffle = &entry;
3340void InstructionSelectorT::VisitI8x16Shuffle(OpIndex node) {
3343 auto view = this->simd_shuffle_view(node);
3344 CanonicalizeShuffle(view, shuffle, &is_swizzle);
3347 static const int kMaxImms = 6;
3348 uint32_t imms[kMaxImms];
3350 static const int kMaxTemps = 2;
3351 InstructionOperand temps[kMaxTemps];
3353 IA32OperandGeneratorT g(
this);
3354 bool use_avx = CpuFeatures::IsSupported(AVX);
3356 bool no_same_as_first = use_avx || is_swizzle;
3361 bool src0_needs_reg =
true;
3362 bool src1_needs_reg =
false;
3366 uint8_t shuffle32x4[4];
3367 uint8_t shuffle16x8[8];
3369 const ShuffleEntry* arch_shuffle;
3370 if (wasm::SimdShuffle::TryMatchConcat(shuffle, &
offset)) {
3371 if (wasm::SimdShuffle::TryMatch32x4Rotate(shuffle, shuffle32x4,
3373 uint8_t shuffle_mask = wasm::SimdShuffle::PackShuffle4(shuffle32x4);
3374 opcode = kIA32S32x4Rotate;
3375 imms[imm_count++] = shuffle_mask;
3378 SwapShuffleInputs(view);
3380 no_same_as_first = use_avx;
3381 opcode = kIA32S8x16Alignr;
3383 imms[imm_count++] =
offset;
3385 }
else if (TryMatchArchShuffle(shuffle, arch_shuffles,
3388 opcode = use_avx ? arch_shuffle->avx_opcode : arch_shuffle->opcode;
3389 src0_needs_reg = !use_avx || arch_shuffle->src0_needs_reg;
3392 src1_needs_reg = use_avx && arch_shuffle->src1_needs_reg;
3393 no_same_as_first = use_avx;
3394 }
else if (wasm::SimdShuffle::TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
3395 uint8_t shuffle_mask = wasm::SimdShuffle::PackShuffle4(shuffle32x4);
3397 if (wasm::SimdShuffle::TryMatchIdentity(shuffle)) {
3399 OpIndex input = view.input(0);
3402 MarkAsDefined(node);
3403 SetRename(node, input);
3407 opcode = kIA32S32x4Swizzle;
3408 no_same_as_first =
true;
3412 src0_needs_reg =
true;
3413 imms[imm_count++] = shuffle_mask;
3418 if (wasm::SimdShuffle::TryMatchBlend(shuffle)) {
3419 opcode = kIA32S16x8Blend;
3420 uint8_t blend_mask = wasm::SimdShuffle::PackBlend4(shuffle32x4);
3421 imms[imm_count++] = blend_mask;
3423 opcode = kIA32S32x4Shuffle;
3424 no_same_as_first =
true;
3428 src0_needs_reg =
true;
3429 src1_needs_reg =
true;
3430 imms[imm_count++] = shuffle_mask;
3431 int8_t blend_mask = wasm::SimdShuffle::PackBlend4(shuffle32x4);
3432 imms[imm_count++] = blend_mask;
3435 }
else if (wasm::SimdShuffle::TryMatch16x8Shuffle(shuffle, shuffle16x8)) {
3437 if (wasm::SimdShuffle::TryMatchBlend(shuffle)) {
3438 opcode = kIA32S16x8Blend;
3439 blend_mask = wasm::SimdShuffle::PackBlend8(shuffle16x8);
3440 imms[imm_count++] = blend_mask;
3441 }
else if (wasm::SimdShuffle::TryMatchSplat<8>(shuffle, &index)) {
3442 opcode = kIA32S16x8Dup;
3443 src0_needs_reg =
false;
3444 imms[imm_count++] =
index;
3445 }
else if (TryMatch16x8HalfShuffle(shuffle16x8, &blend_mask)) {
3446 opcode = is_swizzle ? kIA32S16x8HalfShuffle1 : kIA32S16x8HalfShuffle2;
3448 no_same_as_first =
true;
3449 src0_needs_reg =
false;
3450 uint8_t mask_lo = wasm::SimdShuffle::PackShuffle4(shuffle16x8);
3451 uint8_t mask_hi = wasm::SimdShuffle::PackShuffle4(shuffle16x8 + 4);
3452 imms[imm_count++] = mask_lo;
3453 imms[imm_count++] = mask_hi;
3454 if (!is_swizzle) imms[imm_count++] = blend_mask;
3456 }
else if (wasm::SimdShuffle::TryMatchSplat<16>(shuffle, &index)) {
3457 opcode = kIA32S8x16Dup;
3458 no_same_as_first = use_avx;
3459 src0_needs_reg =
true;
3460 imms[imm_count++] =
index;
3462 if (opcode == kIA32I8x16Shuffle) {
3464 no_same_as_first = !is_swizzle;
3465 src0_needs_reg = !no_same_as_first;
3466 imms[imm_count++] = wasm::SimdShuffle::Pack4Lanes(shuffle);
3467 imms[imm_count++] = wasm::SimdShuffle::Pack4Lanes(shuffle + 4);
3468 imms[imm_count++] = wasm::SimdShuffle::Pack4Lanes(shuffle + 8);
3469 imms[imm_count++] = wasm::SimdShuffle::Pack4Lanes(shuffle + 12);
3470 temps[temp_count++] = g.TempRegister();
3475 OpIndex input0 = view.input(0);
3476 InstructionOperand dst =
3477 no_same_as_first ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
3479 InstructionOperand src0 = g.UseRegister(input0);
3480 USE(src0_needs_reg);
3483 InstructionOperand inputs[2 + kMaxImms + kMaxTemps];
3486 OpIndex input1 = view.input(1);
3489 USE(src1_needs_reg);
3491 for (
int i = 0;
i < imm_count; ++
i) {
3494 Emit(opcode, 1, &dst, input_count, inputs, temp_count, temps);
3497void InstructionSelectorT::VisitI8x16Swizzle(OpIndex node) {
3500 OpIndex left = this->input_at(node, 0);
3501 OpIndex right = this->input_at(node, 1);
3502 const Simd128BinopOp& binop = this->
Get(node).template Cast<Simd128BinopOp>();
3503 DCHECK(binop.kind ==
any_of(Simd128BinopOp::Kind::kI8x16Swizzle,
3504 Simd128BinopOp::Kind::kI8x16RelaxedSwizzle));
3505 bool relaxed = binop.kind == Simd128BinopOp::Kind::kI8x16RelaxedSwizzle;
3507 op |= MiscField::encode(
true);
3513 if (
auto c = right_op.TryCast<Simd128ConstantOp>()) {
3514 std::array<uint8_t, kSimd128Size> imms;
3515 std::memcpy(&imms, c->value, kSimd128Size);
3516 op |= MiscField::encode(wasm::SimdSwizzle::AllInRangeOrTopBitSet(imms));
3520 IA32OperandGeneratorT g(
this);
3521 InstructionOperand temps[] = {g.TempRegister()};
3524 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node),
3525 g.UseRegister(left), g.UseRegister(right),
arraysize(temps), temps);
3528void InstructionSelectorT::VisitSetStackPointer(OpIndex node) {
3529 OperandGenerator g(
this);
3530 auto input = g.UseAny(this->input_at(node, 0));
3531 Emit(kArchSetStackPointer, 0,
nullptr, 1, &input);
3536void VisitMinOrMax(InstructionSelectorT* selector, OpIndex node,
3537 ArchOpcode opcode,
bool flip_inputs) {
3540 IA32OperandGeneratorT g(selector);
3541 InstructionOperand dst = selector->IsSupported(AVX)
3542 ? g.DefineAsRegister(node)
3543 : g.DefineSameAsFirst(node);
3547 selector->Emit(opcode, dst, g.UseRegister(selector->input_at(node, 1)),
3548 g.UseRegister(selector->input_at(node, 0)));
3550 selector->Emit(opcode, dst, g.UseRegister(selector->input_at(node, 0)),
3551 g.UseRegister(selector->input_at(node, 1)));
3556void InstructionSelectorT::VisitF32x4Pmin(OpIndex node) {
3557 VisitMinOrMax(
this, node, kIA32Minps,
true);
3560void InstructionSelectorT::VisitF32x4Pmax(OpIndex node) {
3561 VisitMinOrMax(
this, node, kIA32Maxps,
true);
3564void InstructionSelectorT::VisitF64x2Pmin(OpIndex node) {
3565 VisitMinOrMax(
this, node, kIA32Minpd,
true);
3568void InstructionSelectorT::VisitF64x2Pmax(OpIndex node) {
3569 VisitMinOrMax(
this, node, kIA32Maxpd,
true);
3572void InstructionSelectorT::VisitF32x4RelaxedMin(OpIndex node) {
3573 VisitMinOrMax(
this, node, kIA32Minps,
false);
3576void InstructionSelectorT::VisitF32x4RelaxedMax(OpIndex node) {
3577 VisitMinOrMax(
this, node, kIA32Maxps,
false);
3580void InstructionSelectorT::VisitF64x2RelaxedMin(OpIndex node) {
3581 VisitMinOrMax(
this, node, kIA32Minpd,
false);
3584void InstructionSelectorT::VisitF64x2RelaxedMax(OpIndex node) {
3585 VisitMinOrMax(
this, node, kIA32Maxpd,
false);
3590void VisitExtAddPairwise(InstructionSelectorT* selector, OpIndex node,
3591 ArchOpcode opcode,
bool need_temp) {
3592 IA32OperandGeneratorT g(selector);
3593 InstructionOperand operand0 = g.UseRegister(selector->input_at(node, 0));
3594 InstructionOperand dst = (selector->IsSupported(AVX))
3595 ? g.DefineAsRegister(node)
3596 : g.DefineSameAsFirst(node);
3598 InstructionOperand temps[] = {g.TempRegister()};
3599 selector->Emit(opcode, dst, operand0,
arraysize(temps), temps);
3601 selector->Emit(opcode, dst, operand0);
3606void InstructionSelectorT::VisitI32x4ExtAddPairwiseI16x8S(OpIndex node) {
3607 VisitExtAddPairwise(
this, node, kIA32I32x4ExtAddPairwiseI16x8S,
true);
3610void InstructionSelectorT::VisitI32x4ExtAddPairwiseI16x8U(OpIndex node) {
3611 VisitExtAddPairwise(
this, node, kIA32I32x4ExtAddPairwiseI16x8U,
false);
3614void InstructionSelectorT::VisitI16x8ExtAddPairwiseI8x16S(OpIndex node) {
3615 VisitExtAddPairwise(
this, node, kIA32I16x8ExtAddPairwiseI8x16S,
true);
3618void InstructionSelectorT::VisitI16x8ExtAddPairwiseI8x16U(OpIndex node) {
3619 VisitExtAddPairwise(
this, node, kIA32I16x8ExtAddPairwiseI8x16U,
true);
3622void InstructionSelectorT::VisitI8x16Popcnt(OpIndex node) {
3623 IA32OperandGeneratorT g(
this);
3624 InstructionOperand dst = CpuFeatures::IsSupported(AVX)
3625 ? g.DefineAsRegister(node)
3626 : g.DefineAsRegister(node);
3627 InstructionOperand temps[] = {g.TempSimd128Register(), g.TempRegister()};
3628 Emit(kIA32I8x16Popcnt, dst, g.UseUniqueRegister(this->input_at(node, 0)),
3632void InstructionSelectorT::VisitF64x2ConvertLowI32x4U(OpIndex node) {
3633 IA32OperandGeneratorT g(
this);
3634 InstructionOperand temps[] = {g.TempRegister()};
3635 InstructionOperand dst =
3636 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
3637 Emit(kIA32F64x2ConvertLowI32x4U, dst, g.UseRegister(this->input_at(node, 0)),
3641void InstructionSelectorT::VisitI32x4TruncSatF64x2SZero(OpIndex node) {
3642 IA32OperandGeneratorT g(
this);
3643 InstructionOperand temps[] = {g.TempRegister()};
3644 if (IsSupported(AVX)) {
3646 Emit(kIA32I32x4TruncSatF64x2SZero, g.DefineAsRegister(node),
3647 g.UseUniqueRegister(this->input_at(node, 0)),
arraysize(temps), temps);
3649 Emit(kIA32I32x4TruncSatF64x2SZero, g.DefineSameAsFirst(node),
3650 g.UseRegister(this->input_at(node, 0)),
arraysize(temps), temps);
3654void InstructionSelectorT::VisitI32x4TruncSatF64x2UZero(OpIndex node) {
3655 IA32OperandGeneratorT g(
this);
3656 InstructionOperand temps[] = {g.TempRegister()};
3657 InstructionOperand dst =
3658 IsSupported(AVX) ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node);
3659 Emit(kIA32I32x4TruncSatF64x2UZero, dst,
3660 g.UseRegister(this->input_at(node, 0)),
arraysize(temps), temps);
3663void InstructionSelectorT::VisitI32x4RelaxedTruncF64x2SZero(OpIndex node) {
3664 VisitRRSimd(
this, node, kIA32Cvttpd2dq);
3667void InstructionSelectorT::VisitI32x4RelaxedTruncF64x2UZero(OpIndex node) {
3668 VisitFloatUnop(
this, node, this->input_at(node, 0),
3669 kIA32I32x4TruncF64x2UZero);
3672void InstructionSelectorT::VisitI32x4RelaxedTruncF32x4S(OpIndex node) {
3673 VisitRRSimd(
this, node, kIA32Cvttps2dq);
3676void InstructionSelectorT::VisitI32x4RelaxedTruncF32x4U(OpIndex node) {
3677 IA32OperandGeneratorT g(
this);
3678 OpIndex input = this->input_at(node, 0);
3679 InstructionOperand temps[] = {g.TempSimd128Register()};
3681 if (IsSupported(AVX)) {
3682 Emit(kIA32I32x4TruncF32x4U, g.DefineAsRegister(node), g.UseRegister(input),
3685 Emit(kIA32I32x4TruncF32x4U, g.DefineSameAsFirst(node), g.UseRegister(input),
3690void InstructionSelectorT::VisitI64x2GtS(OpIndex node) {
3691 IA32OperandGeneratorT g(
this);
3692 if (CpuFeatures::IsSupported(AVX)) {
3693 Emit(kIA32I64x2GtS, g.DefineAsRegister(node),
3694 g.UseRegister(this->input_at(node, 0)),
3695 g.UseRegister(this->input_at(node, 1)));
3696 }
else if (CpuFeatures::IsSupported(SSE4_2)) {
3697 Emit(kIA32I64x2GtS, g.DefineSameAsFirst(node),
3698 g.UseRegister(this->input_at(node, 0)),
3699 g.UseRegister(this->input_at(node, 1)));
3701 Emit(kIA32I64x2GtS, g.DefineAsRegister(node),
3702 g.UseUniqueRegister(this->input_at(node, 0)),
3703 g.UseUniqueRegister(this->input_at(node, 1)));
3707void InstructionSelectorT::VisitI64x2GeS(OpIndex node) {
3708 IA32OperandGeneratorT g(
this);
3709 if (CpuFeatures::IsSupported(AVX)) {
3710 Emit(kIA32I64x2GeS, g.DefineAsRegister(node),
3711 g.UseRegister(this->input_at(node, 0)),
3712 g.UseRegister(this->input_at(node, 1)));
3713 }
else if (CpuFeatures::IsSupported(SSE4_2)) {
3714 Emit(kIA32I64x2GeS, g.DefineAsRegister(node),
3715 g.UseUniqueRegister(this->input_at(node, 0)),
3716 g.UseRegister(this->input_at(node, 1)));
3718 Emit(kIA32I64x2GeS, g.DefineAsRegister(node),
3719 g.UseUniqueRegister(this->input_at(node, 0)),
3720 g.UseUniqueRegister(this->input_at(node, 1)));
3724void InstructionSelectorT::VisitI64x2Abs(OpIndex node) {
3725 VisitRRSimd(
this, node, kIA32I64x2Abs, kIA32I64x2Abs);
3728void InstructionSelectorT::VisitF64x2PromoteLowF32x4(OpIndex node) {
3729 IA32OperandGeneratorT g(
this);
3735 OpIndex input = this->input_at(node, 0);
3736 LoadTransformMatcher
m(input);
3738 if (
m.Is(LoadTransformation::kS128Load64Zero) && CanCover(node, input)) {
3741 MemoryAccessKind::kProtectedByTrapHandler);
3744 MarkAsDefined(input);
3745 VisitLoad(node, input, code);
3754void VisitRelaxedLaneSelect(InstructionSelectorT* selector, OpIndex node,
3755 InstructionCode code = kIA32Pblendvb) {
3756 IA32OperandGeneratorT g(selector);
3760 if (selector->IsSupported(AVX)) {
3761 selector->Emit(code, g.DefineAsRegister(node),
3762 g.UseRegister(selector->input_at(node, 2)),
3763 g.UseRegister(selector->input_at(node, 1)),
3764 g.UseRegister(selector->input_at(node, 0)));
3768 selector->Emit(code, g.DefineSameAsFirst(node),
3769 g.UseRegister(selector->input_at(node, 2)),
3770 g.UseRegister(selector->input_at(node, 1)),
3771 g.UseFixed(selector->input_at(node, 0), xmm0));
3776void InstructionSelectorT::VisitI8x16RelaxedLaneSelect(OpIndex node) {
3777 VisitRelaxedLaneSelect(
this, node);
3779void InstructionSelectorT::VisitI16x8RelaxedLaneSelect(OpIndex node) {
3780 VisitRelaxedLaneSelect(
this, node);
3782void InstructionSelectorT::VisitI32x4RelaxedLaneSelect(OpIndex node) {
3783 VisitRelaxedLaneSelect(
this, node, kIA32Blendvps);
3785void InstructionSelectorT::VisitI64x2RelaxedLaneSelect(OpIndex node) {
3786 VisitRelaxedLaneSelect(
this, node, kIA32Blendvpd);
3789void InstructionSelectorT::VisitF64x2Qfma(OpIndex node) {
3793void InstructionSelectorT::VisitF64x2Qfms(OpIndex node) {
3797void InstructionSelectorT::VisitF32x4Qfma(OpIndex node) {
3801void InstructionSelectorT::VisitF32x4Qfms(OpIndex node) {
3805void InstructionSelectorT::VisitF16x8Qfma(OpIndex node) {
UNIMPLEMENTED(); }
3807void InstructionSelectorT::VisitF16x8Qfms(OpIndex node) {
UNIMPLEMENTED(); }
3809void InstructionSelectorT::VisitI16x8DotI8x16I7x16S(OpIndex node) {
3810 IA32OperandGeneratorT g(
this);
3811 Emit(kIA32I16x8DotI8x16I7x16S, g.DefineAsRegister(node),
3812 g.UseUniqueRegister(this->input_at(node, 0)),
3813 g.UseRegister(this->input_at(node, 1)));
3816void InstructionSelectorT::VisitI32x4DotI8x16I7x16AddS(OpIndex node) {
3817 IA32OperandGeneratorT g(
this);
3818 InstructionOperand temps[] = {g.TempSimd128Register()};
3819 Emit(kIA32I32x4DotI8x16I7x16AddS, g.DefineSameAsInput(node, 2),
3820 g.UseUniqueRegister(this->input_at(node, 0)),
3821 g.UseUniqueRegister(this->input_at(node, 1)),
3822 g.UseUniqueRegister(this->input_at(node, 2)),
arraysize(temps), temps);
3826void InstructionSelectorT::AddOutputToSelectContinuation(OperandGeneratorT* g,
3827 int first_input_index,
3833MachineOperatorBuilder::Flags
3834InstructionSelector::SupportedMachineOperatorFlags() {
3835 MachineOperatorBuilder::Flags flags =
3836 MachineOperatorBuilder::kWord32ShiftIsSafe |
3837 MachineOperatorBuilder::kWord32Ctz | MachineOperatorBuilder::kWord32Rol;
3838 if (CpuFeatures::IsSupported(POPCNT)) {
3839 flags |= MachineOperatorBuilder::kWord32Popcnt;
3841 if (CpuFeatures::IsSupported(SSE4_1)) {
3842 flags |= MachineOperatorBuilder::kFloat32RoundDown |
3843 MachineOperatorBuilder::kFloat64RoundDown |
3844 MachineOperatorBuilder::kFloat32RoundUp |
3845 MachineOperatorBuilder::kFloat64RoundUp |
3846 MachineOperatorBuilder::kFloat32RoundTruncate |
3847 MachineOperatorBuilder::kFloat64RoundTruncate |
3848 MachineOperatorBuilder::kFloat32RoundTiesEven |
3849 MachineOperatorBuilder::kFloat64RoundTiesEven;
3855MachineOperatorBuilder::AlignmentRequirements
3856InstructionSelector::AlignmentRequirements() {
3857 return MachineOperatorBuilder::AlignmentRequirements::
3858 FullUnalignedAccessSupport();
interpreter::OperandScale scale
static constexpr U encode(T value)
static bool IsSupported(CpuFeature f)
static constexpr MachineType Float64()
static constexpr MachineType Uint8()
constexpr MachineRepresentation representation() const
static constexpr MachineType Int32()
static constexpr MachineType Simd128()
static constexpr MachineType Uint32()
static constexpr MachineType Uint16()
static constexpr MachineType Int16()
static constexpr MachineType Float32()
static constexpr MachineType None()
static constexpr MachineType Int8()
static intptr_t RootRegisterOffsetForExternalReference(Isolate *isolate, const ExternalReference &reference)
int AllocateSpillSlot(int width, int alignment=0, bool is_tagged=false)
bool ValueFitsIntoImmediate(int64_t value) const
AddressingMode GetEffectiveAddressMemoryOperand(OpIndex node, InstructionOperand inputs[], size_t *input_count, RegisterMode register_mode=RegisterMode::kRegister)
bool CanBeBetterLeftOperand(OpIndex node) const
InstructionOperand GetEffectiveIndexOperand(OpIndex index, AddressingMode *mode)
AddressingMode GenerateMemoryOperandInputs(OptionalOpIndex index, int scale, OpIndex base, int32_t displacement, DisplacementMode displacement_mode, InstructionOperand inputs[], size_t *input_count, RegisterMode register_mode=RegisterMode::kRegister)
bool CanBeImmediate(OpIndex node)
bool CanBeMemoryOperand(InstructionCode opcode, OpIndex node, OpIndex input, int effect_level)
InstructionOperand UseByteRegister(OpIndex node)
int32_t GetImmediateIntegerValue(OpIndex node)
IA32OperandGeneratorT(InstructionSelectorT *selector)
int GetVirtualRegister(turboshaft::OpIndex node)
void MarkAsSimd128(turboshaft::OpIndex node)
void VisitWordCompareZero(turboshaft::OpIndex user, turboshaft::OpIndex value, FlagsContinuation *cont)
FlagsCondition GetComparisonFlagCondition(const turboshaft::ComparisonOp &op) const
void EmitPrepareArguments(ZoneVector< PushParameter > *arguments, const CallDescriptor *call_descriptor, turboshaft::OpIndex node)
Instruction * Emit(InstructionCode opcode, InstructionOperand output, size_t temp_count=0, InstructionOperand *temps=nullptr)
void MarkAsFloat64(turboshaft::OpIndex node)
bool CanCover(turboshaft::OpIndex user, turboshaft::OpIndex node) const
void EmitMoveFPRToParam(InstructionOperand *op, LinkageLocation location)
Instruction * EmitWithContinuation(InstructionCode opcode, FlagsContinuation *cont)
void VisitLoadTransform(Node *node, Node *value, InstructionCode opcode)
bool IsSupported(CpuFeature feature) const
bool IsTailCallAddressImmediate()
void VisitStackPointerGreaterThan(turboshaft::OpIndex node, FlagsContinuation *cont)
void ConsumeEqualZero(turboshaft::OpIndex *user, turboshaft::OpIndex *value, FlagsContinuation *cont)
turboshaft::OptionalOpIndex FindProjection(turboshaft::OpIndex node, size_t projection_index)
void VisitLoad(turboshaft::OpIndex node, turboshaft::OpIndex value, InstructionCode opcode)
PushParameterT PushParameter
bool IsLive(turboshaft::OpIndex node) const
OperandGeneratorT OperandGenerator
int GetEffectLevel(turboshaft::OpIndex node) const
void VisitFloat64Ieee754Binop(turboshaft::OpIndex, InstructionCode code)
auto Inputs(turboshaft::OpIndex node)
void MarkAsFloat32(turboshaft::OpIndex node)
InstructionSequence * sequence() const
void EmitMoveParamToFPR(turboshaft::OpIndex node, int index)
void VisitFloat64Ieee754Unop(turboshaft::OpIndex, InstructionCode code)
void EmitPrepareResults(ZoneVector< PushParameter > *results, const CallDescriptor *call_descriptor, turboshaft::OpIndex node)
Instruction * MarkAsCall()
InstructionOperand TempRegister()
InstructionOperand UseImmediate(int immediate)
InstructionOperand UseFixed(turboshaft::OpIndex node, Register reg)
InstructionOperand DefineSameAsFirst(turboshaft::OpIndex node)
InstructionOperand UseUniqueRegister(turboshaft::OpIndex node)
InstructionOperand TempImmediate(int32_t imm)
InstructionSelectorT * selector() const
InstructionOperand UseRegister(turboshaft::OpIndex node)
InstructionOperand DefineAsFixed(turboshaft::OpIndex node, Register reg)
InstructionOperand UseRegisterWithMode(turboshaft::OpIndex node, RegisterMode register_mode)
LoadRepresentation loaded_rep() const
MachineType ToMachineType() const
bool Is(V< AnyOrNone > op_idx) const
const Operation & Get(V< AnyOrNone > op_idx) const
bool MatchIntegralZero(V< Any > matched) const
const underlying_operation_t< Op > * TryCast(V< AnyOrNone > op_idx) const
bool MatchExternalConstant(V< Any > matched, ExternalReference *reference) const
const underlying_operation_t< Op > & Cast(V< AnyOrNone > op_idx) const
bool MatchIntegralWord32Constant(V< Any > matched, uint32_t *constant) const
constexpr OpIndex value() const
constexpr bool valid() const
static constexpr RegisterRepresentation Word32()
static constexpr RegisterRepresentation Float32()
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
other heap size flags(e.g. initial_heap_size) take precedence") DEFINE_SIZE_T( max_shared_heap_size
#define RR_VISITOR(Name, opcode)
#define RO_VISITOR(Name, opcode)
#define SIMD_INT_TYPES(V)
#define SIMD_UNOP_LIST(V)
#define SIMD_BINOP_RRR(V)
#define RO_WITH_TEMP_SIMD_OP_T_LIST(V)
#define SIMD_SHIFT_OPCODES_UNIFED_SSE_AVX(V)
#define SIMD_BINOP_LIST(V)
#define RO_WITH_TEMP_VISITOR(Name, opcode)
#define RRO_FLOAT_OP_T_LIST(V)
#define FLOAT_UNOP_VISITOR(Name, opcode)
#define RRO_FLOAT_VISITOR(Name, opcode)
#define VISIT_ATOMIC_BINOP(op)
#define FLOAT_UNOP_T_LIST(V)
#define RO_WITH_TEMP_SIMD_VISITOR(Name, opcode)
#define RO_WITH_TEMP_OP_T_LIST(V)
#define SIMD_ALLTRUE_LIST(V)
DisplacementMode displacement_mode
#define SIMD_BINOP_UNIFIED_SSE_AVX_LIST(V)
ZoneVector< RpoNumber > & result
int32_t WraparoundNeg32(int32_t x)
int32_t WraparoundAdd32(int32_t lhs, int32_t rhs)
bool any_of(const C &container, const P &predicate)
constexpr size_t input_count()
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
AtomicMemoryOrder AtomicOrder(InstructionSelectorT *selector, OpIndex node)
void VisitAtomicExchange(InstructionSelectorT *selector, OpIndex node, ArchOpcode opcode)
void VisitWord32PairShift(InstructionSelectorT *selector, InstructionCode opcode, OpIndex node)
void VisitRRRR(InstructionSelectorT *selector, ArchOpcode opcode, OpIndex node)
static void VisitRR(InstructionSelectorT *selector, ArchOpcode opcode, OpIndex node)
std::optional< ScaledIndexMatch > TryMatchScaledIndex(InstructionSelectorT *selector, OpIndex node, bool allow_power_of_two_plus_one)
static Instruction * VisitCompare(InstructionSelectorT *selector, InstructionCode opcode, InstructionOperand left, InstructionOperand right, FlagsContinuationT *cont)
void VisitFloat32Compare(InstructionSelectorT *selector, OpIndex node, FlagsContinuationT *cont)
MachineType AtomicOpType(InstructionSelectorT *selector, OpIndex node)
void VisitStoreCommon(InstructionSelectorT *selector, OpIndex node, StoreRepresentation store_rep, std::optional< AtomicMemoryOrder > atomic_order)
static void VisitBinop(InstructionSelectorT *selector, turboshaft::OpIndex node, InstructionCode opcode, bool has_reverse_opcode, InstructionCode reverse_opcode, FlagsContinuationT *cont)
bool MatchScaledIndex(InstructionSelectorT *selector, OpIndex node, OpIndex *index, int *scale, bool *power_of_two_plus_one)
MachineType LoadRepresentation
Instruction * VisitWordCompare(InstructionSelectorT *selector, OpIndex node, InstructionCode opcode, FlagsContinuationT *cont, bool commutative)
void VisitFloat64Compare(InstructionSelectorT *selector, OpIndex node, FlagsContinuationT *cont)
RecordWriteMode WriteBarrierKindToRecordWriteMode(WriteBarrierKind write_barrier_kind)
static void VisitShift(InstructionSelectorT *selector, OpIndex node, ArchOpcode opcode)
void VisitRR(InstructionSelectorT *selector, InstructionCode opcode, OpIndex node)
constexpr int kSimd128Size
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
constexpr bool IsAnyTagged(MachineRepresentation rep)
constexpr int kSystemPointerSize
constexpr bool CanBeTaggedPointer(MachineRepresentation rep)
V8_EXPORT_PRIVATE FlagValues v8_flags
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
#define DCHECK_LE(v1, v2)
#define DCHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
bool IsExternalConstant(turboshaft::OpIndex node) const
turboshaft::OpIndex input_at(turboshaft::OpIndex node, size_t index) const
base::Vector< const turboshaft::OpIndex > inputs(turboshaft::OpIndex node) const
bool IsLoadOrLoadImmutable(turboshaft::OpIndex node) const
LoadView load_view(turboshaft::OpIndex node)
turboshaft::Opcode opcode(turboshaft::OpIndex node) const
int value_input_count(turboshaft::OpIndex node) const
StoreView store_view(turboshaft::OpIndex node)
MemoryRepresentation memory_rep
const underlying_operation_t< Op > * TryCast() const