25 if (v8_flags.trace_wasm_revectorize) { \
27 PrintF(__VA_ARGS__); \
33#define SIMPLE_SIMD_OP(V) \
34 V(F64x2Add, F64x4Add) \
35 V(F32x4Add, F32x8Add) \
36 V(I64x2Add, I64x4Add) \
37 V(I32x4Add, I32x8Add) \
38 V(I16x8Add, I16x16Add) \
39 V(I8x16Add, I8x32Add) \
40 V(F64x2Sub, F64x4Sub) \
41 V(F32x4Sub, F32x8Sub) \
42 V(I64x2Sub, I64x4Sub) \
43 V(I32x4Sub, I32x8Sub) \
44 V(I16x8Sub, I16x16Sub) \
45 V(I8x16Sub, I8x32Sub) \
46 V(F64x2Mul, F64x4Mul) \
47 V(F32x4Mul, F32x8Mul) \
48 V(I64x2Mul, I64x4Mul) \
49 V(I32x4Mul, I32x8Mul) \
50 V(I16x8Mul, I16x16Mul) \
51 V(F64x2Div, F64x4Div) \
52 V(F32x4Div, F32x8Div) \
53 V(I16x8AddSatS, I16x16AddSatS) \
54 V(I16x8SubSatS, I16x16SubSatS) \
55 V(I16x8AddSatU, I16x16AddSatU) \
56 V(I16x8SubSatU, I16x16SubSatU) \
57 V(I8x16AddSatS, I8x32AddSatS) \
58 V(I8x16SubSatS, I8x32SubSatS) \
59 V(I8x16AddSatU, I8x32AddSatU) \
60 V(I8x16SubSatU, I8x32SubSatU) \
65 V(I16x8Eq, I16x16Eq) \
69 V(I64x2GtS, I64x4GtS) \
70 V(I32x4GtS, I32x8GtS) \
71 V(I16x8GtS, I16x16GtS) \
72 V(I8x16GtS, I8x32GtS) \
77 V(I32x4MinS, I32x8MinS) \
78 V(I16x8MinS, I16x16MinS) \
79 V(I8x16MinS, I8x32MinS) \
80 V(I32x4MinU, I32x8MinU) \
81 V(I16x8MinU, I16x16MinU) \
82 V(I8x16MinU, I8x32MinU) \
83 V(I32x4MaxS, I32x8MaxS) \
84 V(I16x8MaxS, I16x16MaxS) \
85 V(I8x16MaxS, I8x32MaxS) \
86 V(I32x4MaxU, I32x8MaxU) \
87 V(I16x8MaxU, I16x16MaxU) \
88 V(I8x16MaxU, I8x32MaxU) \
89 V(F32x4Abs, F32x8Abs) \
90 V(I32x4Abs, I32x8Abs) \
91 V(I16x8Abs, I16x16Abs) \
92 V(I8x16Abs, I8x32Abs) \
93 V(F32x4Neg, F32x8Neg) \
94 V(I32x4Neg, I32x8Neg) \
95 V(I16x8Neg, I16x16Neg) \
96 V(I8x16Neg, I8x32Neg) \
97 V(F64x2Sqrt, F64x4Sqrt) \
98 V(F32x4Sqrt, F32x8Sqrt) \
99 V(F64x2Min, F64x4Min) \
100 V(F32x4Min, F32x8Min) \
101 V(F64x2Max, F64x4Max) \
102 V(F32x4Max, F32x8Max) \
103 V(I64x2Ne, I64x4Ne) \
104 V(I32x4Ne, I32x8Ne) \
105 V(I16x8Ne, I16x16Ne) \
106 V(I8x16Ne, I8x32Ne) \
107 V(I32x4GtU, I32x8GtU) \
108 V(I16x8GtU, I16x16GtU) \
109 V(I8x16GtU, I8x32GtU) \
110 V(I64x2GeS, I64x4GeS) \
111 V(I32x4GeS, I32x8GeS) \
112 V(I16x8GeS, I16x16GeS) \
113 V(I8x16GeS, I8x32GeS) \
114 V(I32x4GeU, I32x8GeU) \
115 V(I16x8GeU, I16x16GeU) \
116 V(I8x16GeU, I8x32GeU) \
117 V(F32x4Pmin, F32x8Pmin) \
118 V(F32x4Pmax, F32x8Pmax) \
119 V(F64x2Pmin, F64x4Pmin) \
120 V(F64x2Pmax, F64x4Pmax) \
121 V(F32x4SConvertI32x4, F32x8SConvertI32x8) \
122 V(F32x4UConvertI32x4, F32x8UConvertI32x8) \
123 V(I32x4UConvertF32x4, I32x8UConvertF32x8) \
124 V(I32x4SConvertF32x4, I32x8SConvertF32x8) \
125 V(S128And, S256And) \
127 V(S128Xor, S256Xor) \
128 V(S128Not, S256Not) \
129 V(S128Select, S256Select) \
130 V(S128AndNot, S256AndNot)
132#define SIMD_SHIFT_OP(V) \
133 V(I64x2Shl, I64x4Shl) \
134 V(I32x4Shl, I32x8Shl) \
135 V(I16x8Shl, I16x16Shl) \
136 V(I32x4ShrS, I32x8ShrS) \
137 V(I16x8ShrS, I16x16ShrS) \
138 V(I64x2ShrU, I64x4ShrU) \
139 V(I32x4ShrU, I32x8ShrU) \
140 V(I16x8ShrU, I16x16ShrU)
142#define SIMD_SIGN_EXTENSION_CONVERT_OP(V) \
143 V(I64x2SConvertI32x4Low, I64x2SConvertI32x4High, I64x4SConvertI32x4) \
144 V(I64x2UConvertI32x4Low, I64x2UConvertI32x4High, I64x4UConvertI32x4) \
145 V(I32x4SConvertI16x8Low, I32x4SConvertI16x8High, I32x8SConvertI16x8) \
146 V(I32x4UConvertI16x8Low, I32x4UConvertI16x8High, I32x8UConvertI16x8) \
147 V(I16x8SConvertI8x16Low, I16x8SConvertI8x16High, I16x16SConvertI8x16) \
148 V(I16x8UConvertI8x16Low, I16x8UConvertI8x16High, I16x16UConvertI8x16)
150#define SIMD_SPLAT_OP(V) \
151 V(I8x16Splat, I8x32Splat) \
152 V(I16x8Splat, I16x16Splat) \
153 V(I32x4Splat, I32x8Splat) \
154 V(I64x2Splat, I64x4Splat)
158bool IsSupportedLoad(
const Node* node) {
159 if (node->opcode() == IrOpcode::kProtectedLoad ||
160 node->opcode() == IrOpcode::kLoad ||
161 node->opcode() == IrOpcode::kLoadTransform) {
168bool IsSupportedLoad(
const ZoneVector<Node*>& node_group) {
169 for (
auto node : node_group) {
170 if (!IsSupportedLoad(node))
return false;
176int64_t GetConstantValue(
const Node* node) {
178 if (node->opcode() == IrOpcode::kInt64Constant) {
184int64_t GetMemoryOffsetValue(
const Node* node) {
185 DCHECK(IsSupportedLoad(node) || node->opcode() == IrOpcode::kStore ||
186 node->opcode() == IrOpcode::kProtectedStore);
188 Node*
offset = node->InputAt(0);
189 if (
offset->opcode() == IrOpcode::kLoadFromObject ||
190 offset->opcode() == IrOpcode::kLoad) {
194 int64_t offset_value = -1;
195 if (
offset->opcode() == IrOpcode::kInt64Add) {
197 offset_value = GetConstantValue(
offset->InputAt(0));
199 offset_value = GetConstantValue(
offset->InputAt(1));
209Node* GetNodeAddress(
const Node* node) {
210 Node* address = node->InputAt(1);
212 if (address->opcode() == IrOpcode::kChangeUint32ToUint64) {
213 address = address->InputAt(0);
218bool IsContinuousAccess(
const ZoneVector<Node*>& node_group) {
220 int64_t previous_offset = GetMemoryOffsetValue(node_group[0]);
221 for (
size_t i = 1;
i < node_group.
size(); ++
i) {
222 int64_t current_offset = GetMemoryOffsetValue(node_group[
i]);
223 int64_t diff = current_offset - previous_offset;
224 if (diff == 8 && node_group[0]->opcode() == IrOpcode::kLoadTransform) {
225 LoadTransformParameters params =
229 TRACE(
"Non-continuous access!\n");
232 TRACE(
"Continuous access with load extend offset!\n");
234 TRACE(
"Non-continuous access!\n");
237 previous_offset = current_offset;
243bool AllConstant(
const ZoneVector<Node*>& node_group) {
244 for (Node* node : node_group) {
253bool AllSameAddress(
const ZoneVector<Node*>& nodes) {
254 Node* address = GetNodeAddress(nodes[0]);
255 for (
size_t i = 1;
i < nodes.
size();
i++) {
256 if (GetNodeAddress(nodes[
i]) != address) {
257 TRACE(
"Diff address #%d,#%d!\n", address->id(),
258 GetNodeAddress(nodes[
i])->
id());
268bool IsSplat(
const T& node_group) {
269 for (
typename T::size_type
i = 1;
i < node_group.size(); ++
i) {
270 if (node_group[
i] != node_group[0]) {
280V8_INLINE static bool OperatorCanBePacked(
const Operator* lhs,
281 const Operator* rhs) {
282 return lhs->opcode() == rhs->opcode() &&
283 lhs->properties() == rhs->properties();
287bool AllPackableOperator(
const ZoneVector<Node*>& node_group) {
288 auto op = node_group[0]->op();
290 if (!OperatorCanBePacked(node_group[
i]->op(), op)) {
297bool ShiftBySameScalar(
const ZoneVector<Node*>& node_group) {
298 auto node0 = node_group[0];
302 if (node_group[
i]->InputAt(1) != node0->InputAt(1)) {
310#define CASE(op_low, op_high, not_used) \
311 case IrOpcode::k##op_low: \
312 case IrOpcode::k##op_high:
323bool MaybePackSignExtensionOp(
const ZoneVector<Node*>& node_group) {
324#define CHECK_SIGN_EXTENSION_CASE(op_low, op_high, not_used) \
325 case IrOpcode::k##op_low: { \
326 if (node_group[1]->opcode() == IrOpcode::k##op_high && \
327 node_group[0]->InputAt(0) == node_group[1]->InputAt(0)) { \
332 switch (node_group[0]->opcode()) {
338#undef CHECK_SIGN_EXTENSION_CASE
342class EffectChainIterator {
344 explicit EffectChainIterator(Node* node) :
node_(node),
prev_(nullptr) {}
348 node_ = EffectInputOf(node_);
357 Node* Next() {
return EffectInputOf(node_); }
359 void Set(Node* node) {
364 Node* operator*() {
return node_; }
367 Node* EffectInputOf(Node* node) {
368 DCHECK(IsSupportedLoad(node));
369 return node->InputAt(2);
376void InsertAfter(EffectChainIterator& dest, EffectChainIterator& src) {
377 Node* dest_next = dest.Next();
387 return GetMemoryOffsetValue(lhs) < GetMemoryOffsetValue(rhs);
397 nodes_[0]->op()->mnemonic());
408 if (!NodeProperties::IsSimd128Operation(node_group[0]) &&
409 (op != IrOpcode::kStore) && (op != IrOpcode::kProtectedStore) &&
410 (op != IrOpcode::kLoad) && (op != IrOpcode::kProtectedLoad) &&
411 (op != IrOpcode::kPhi) && (op != IrOpcode::kLoopExitValue) &&
412 (op != IrOpcode::kExtractF128)) {
417 if (AllConstant(node_group)) {
418 TRACE(
"%s(#%d, #%d) are constantant, not supported yet!\n",
419 node_group[0]->op()->mnemonic(), node_group[0]->
id(),
420 node_group[1]->
id());
423 if (IsSignExtensionOperation(op)) {
424 if (MaybePackSignExtensionOp(node_group)) {
427 TRACE(
"%s(#%d, #%d) are not (low, high) sign extension pair\n",
428 node_group[0]->op()->mnemonic(), node_group[0]->
id(),
429 node_group[1]->
id());
433 if (!AllPackableOperator(node_group)) {
435 "%s(#%d, #%d) have different op, and are not sign extension operator\n",
436 node_group[0]->op()->mnemonic(), node_group[0]->
id(),
437 node_group[1]->
id());
444 TRACE(
"PackNode %s(#%d:, #%d)\n", node_group[0]->op()->mnemonic(),
445 node_group[0]->
id(), node_group[1]->
id());
447 for (
Node* node : node_group) {
454 int start_index,
int count,
457 for (
int i = start_index;
i < start_index +
count; ++
i) {
460 for (
size_t j = 0; j < node_group.
size(); j++) {
461 Node* node = node_group[j];
484 TRACE(
"Stack Push (%d %s, %d %s)\n", node_group[0]->
id(),
485 node_group[0]->op()->mnemonic(), node_group[1]->
id(),
486 node_group[1]->op()->mnemonic());
487 for (
auto node : node_group) {
490 stack_.push({node_group});
496 TRACE(
"Stack Pop (%d %s, %d %s)\n", node_group[0]->
id(),
497 node_group[0]->op()->mnemonic(), node_group[1]->
id(),
498 node_group[1]->op()->mnemonic());
499 for (
auto node : node_group) {
510 for (
auto node : node_group) {
511 if (
OnStack(node))
return true;
533 for (
Node* load : loads) {
534 if (visited.find(load) != visited.end())
continue;
535 visited.insert(load);
537 EffectChainIterator dest(load);
538 EffectChainIterator it(dest.Next());
540 if (std::find(loads.
begin(), loads.
end(), *it) != loads.
end()) {
542 if (dest.Next() != *it) {
543 Node* prev = it.Prev();
544 InsertAfter(dest, it);
555 DCHECK(IsSupportedLoad(node_group));
557 TRACE(
"Enter IsSideEffectFreeLoad (%d %s, %d %s)\n", node_group[0]->
id(),
558 node_group[0]->op()->mnemonic(), node_group[1]->
id(),
559 node_group[1]->op()->mnemonic());
563 if (node_group[0] != node_group[1] &&
568 std::stack<Node*> to_visit;
569 std::unordered_set<Node*> visited;
571 for (
size_t i = 0, e = node_group.
size();
i < e;
i++) {
572 Node* load = node_group[
i];
575 if (std::find(node_group.
begin(), node_group.
end(), input) ==
577 to_visit.push(input);
585 while (!to_visit.empty()) {
586 Node* input = to_visit.top();
588 TRACE(
"IsSideEffectFreeLoad visit (%d %s)\n", input->id(),
589 input->op()->mnemonic());
590 if (visited.find(input) == visited.end()) {
591 visited.insert(input);
594 TRACE(
"Has internal dependency because (%d %s) on stack\n", input->id(),
595 input->op()->mnemonic());
604 to_visit.push(input->InputAt(
i));
613 TRACE(
"Enter %s\n", __func__);
623 TRACE(
"Enter %s\n", __func__);
626 Node* node0 = node_group[0];
627 Node* node1 = node_group[1];
630 TRACE(
"Failed due to max recursion depth!\n");
636 TRACE(
"Failed due to (%d %s, %d %s) on stack!\n", node0->
id(),
637 node0->
op()->mnemonic(), node1->
id(), node1->
op()->mnemonic());
647 DCHECK(AllConstant(node_group) || AllPackableOperator(node_group) ||
648 MaybePackSignExtensionOp(node_group));
651 for (
Node* node : node_group) {
653 if (!p->IsSame(node_group)) {
655 TRACE(
"Failed due to partial overlap at #%d,%s!\n", node->id(),
656 node->op()->mnemonic());
661 TRACE(
"Perfect diamond merge at #%d,%s\n", node->id(),
662 node->op()->mnemonic());
667 if (node0->
opcode() == IrOpcode::kS128Zero) {
672 if (node0->
opcode() == IrOpcode::kS128Const) {
677 if (node0->
opcode() == IrOpcode::kExtractF128) {
679 TRACE(
"Extract leaf node from #%d,%s!\n", source->id(),
680 source->op()->mnemonic());
687 TRACE(
"Added a pair of Extract.\n");
692 TRACE(
"Failed due to ExtractF128!\n");
696 if (IsSupportedLoad(node0)) {
697 TRACE(
"Load leaf node\n");
698 if (!AllSameAddress(node_group)) {
699 TRACE(
"Failed due to different load addr!\n");
705 if (node0->
opcode() == IrOpcode::kProtectedLoad &&
713 TRACE(
"Failed due to dependency check\n");
720 std::partial_sort_copy(node_group.
begin(), node_group.
end(),
721 sorted_node_group.
begin(), sorted_node_group.
end(),
723 if (!IsContinuousAccess(sorted_node_group)) {
724 TRACE(
"Failed due to non-continuous load!\n");
728 }
else if (node0->
opcode() == IrOpcode::kLoadTransform) {
731 TRACE(
"LoadTransform failed due to unsupported type #%d!\n",
738 TRACE(
"Failed due to unsupported splat!\n");
748 int value_in_count = node0->
op()->ValueInputCount();
750#define CASE(op128, op256) case IrOpcode::k##op128:
751#define SIGN_EXTENSION_CASE(op_low, not_used1, not_used2) \
752 case IrOpcode::k##op_low:
753 switch (node0->
opcode()) {
754 case IrOpcode::kPhi: {
755 TRACE(
"Added a vector of PHI nodes.\n");
765 case IrOpcode::kLoopExitValue: {
775 case IrOpcode::kI8x16Shuffle: {
782 IrOpcode::kProtectedLoad) ||
785 IrOpcode::kProtectedLoad)) {
789 TRACE(
"Failed to match splat\n");
800 TRACE(
"Added a vector of %s.\n", node0->
op()->mnemonic());
807 if (ShiftBySameScalar(node_group)) {
808 TRACE(
"Added a vector of %s.\n", node0->
op()->mnemonic());
814 TRACE(
"Failed due to shift with different scalar!\n");
818 TRACE(
"add a vector of sign extension op and stop building tree\n");
824 TRACE(
"Added a vector of %s.\n", node0->
op()->mnemonic());
826 TRACE(
"Failed due to different splat input");
836 case IrOpcode::kStore:
837 case IrOpcode::kProtectedStore: {
838 TRACE(
"Added a vector of stores.\n");
839 if (!AllSameAddress(node_group)) {
840 TRACE(
"Failed due to different store addr!\n");
848 TRACE(
"Default branch #%d:%s\n", node0->
id(), node0->
op()->mnemonic());
852#undef SIGN_EXTENSION_CASE
862 TRACE(
"%s, Packed node:\n", info);
863 if (!
v8_flags.trace_wasm_revectorize) {
870template <
typename FunctionType>
872 std::unordered_set<PackNode const*> visited;
875 PackNode const* pnode = entry.second;
876 if (!pnode || visited.find(pnode) != visited.end()) {
879 visited.insert(pnode);
892 group_of_stores_(zone),
894 support_simd256_(false) {
902 TRACE(
"Enter %s\n", __func__);
904 int save = 0, cost = 0;
912 if (op == IrOpcode::kLoopExitValue || op == IrOpcode::kExtractF128) {
920 for (
size_t i = 0;
i < nodes.
size();
i++) {
921 if (
i > 0 && nodes[
i] == nodes[0])
continue;
923 for (
auto edge : nodes[
i]->use_edges()) {
925 Node* useNode = edge.from();
927 useNode->
opcode() != IrOpcode::kLoopExitValue) {
928 TRACE(
"External use edge: (%d:%s) -> (%d:%s)\n", useNode->
id(),
929 useNode->
op()->mnemonic(), nodes[
i]->id(),
930 nodes[
i]->op()->mnemonic());
940 TRACE(
"Save: %d, cost: %d\n", save, cost);
948 DCHECK(nodes[0] == nodes[1] ||
953 for (
size_t i = 0;
i < nodes.
size();
i++) {
954 Node* node128 = nodes[
i];
956 if (effect == pnode)
continue;
960 input = node128->
InputAt(index);
966 PackNode* pnode,
int effect_index) {
969 inputs[0] = node->InputAt(0);
970 inputs[1] = node->InputAt(1);
974 inputs[effect_index + 1] = node->InputAt(effect_index + 1);
978 TRACE(
"Enter %s with PackNode\n", __func__);
983 TRACE(
"Diamond merged for #%d:%s\n", node0->
id(), node0->
op()->mnemonic());
988 TRACE(
"Vectorize #%d:%s, input count: %d\n", node0->
id(),
989 node0->
op()->mnemonic(), input_count);
993 Node* source =
nullptr;
996 for (
int i = 0;
i < input_count;
i++) inputs[
i] = dead;
999 case IrOpcode::kPhi: {
1007 case IrOpcode::kLoopExitValue: {
1015#define SIMPLE_CASE(from, to) \
1016 case IrOpcode::k##from: \
1017 new_op = mcgraph_->machine()->to(); \
1021#undef SIMPLE_SIMD_OP
1023#define SHIFT_CASE(from, to) \
1024 case IrOpcode::k##from: { \
1025 DCHECK(ShiftBySameScalar(pnode->Nodes())); \
1026 new_op = mcgraph_->machine()->to(); \
1027 inputs[1] = node0->InputAt(1); \
1034#define SIGN_EXTENSION_CONVERT_CASE(from, not_used, to) \
1035 case IrOpcode::k##from: { \
1036 DCHECK_EQ(node0->InputAt(0), pnode->Nodes()[1]->InputAt(0)); \
1037 new_op = mcgraph_->machine()->to(); \
1038 inputs[0] = node0->InputAt(0); \
1042#undef SIGN_EXTENSION_CONVERT_CASE
1043#undef SIMD_SIGN_EXTENSION_CONVERT_OP
1045#define SPLAT_CASE(from, to) \
1046 case IrOpcode::k##from: \
1047 new_op = mcgraph_->machine()->to(); \
1048 inputs[0] = node0->InputAt(0); \
1053 case IrOpcode::kI8x16Shuffle: {
1076 DCHECK_EQ(source->opcode(), IrOpcode::kProtectedLoad);
1085 inputs[0] = source->InputAt(0);
1088 inputs[1] = source->InputAt(1);
1089 inputs[2] = source->InputAt(2);
1090 inputs[3] = source->InputAt(3);
1095 uint8_t new_shuffle[32];
1100 for (
int i = 0;
i < 16; ++
i) {
1101 new_shuffle[
i] = shuffle0[
i] % 16;
1102 new_shuffle[
i + 16] = 16 + shuffle1[
i] % 16;
1105 for (
int i = 0;
i < 16; ++
i) {
1106 if (shuffle0[
i] < 16) {
1107 new_shuffle[
i] = shuffle0[
i];
1109 new_shuffle[
i] = 16 + shuffle0[
i];
1112 if (shuffle1[
i] < 16) {
1113 new_shuffle[
i + 16] = 16 + shuffle1[
i];
1115 new_shuffle[
i + 16] = 32 + shuffle1[
i];
1124 case IrOpcode::kS128Zero: {
1128 case IrOpcode::kS128Const: {
1133 value[
i] = value0[
i];
1134 value[
i + 16] = value1[
i];
1139 case IrOpcode::kProtectedLoad: {
1146 case IrOpcode::kLoad: {
1153 case IrOpcode::kProtectedStore: {
1161 case IrOpcode::kStore: {
1171 case IrOpcode::kLoadTransform: {
1176 switch (params.transformation) {
1217 case IrOpcode::kExtractF128: {
1227 if (new_op !=
nullptr) {
1232 for (
int i = 0;
i < input_count;
i++) {
1233 if (inputs[
i] == dead) {
1239 for (
size_t i = 0;
i < nodes.
size();
i++) {
1240 if (
i > 0 && nodes[
i] == nodes[
i - 1])
continue;
1241 Node* input_128 =
nullptr;
1242 for (
auto edge : nodes[
i]->use_edges()) {
1243 Node* useNode = edge.from();
1247 TRACE(
"Replace Value Edge from %d:%s, to %d:%s\n", useNode->
id(),
1248 useNode->
op()->mnemonic(), edge.to()->id(),
1249 edge.to()->op()->mnemonic());
1252 TRACE(
"Create ExtractF128(%lu) node from #%d\n",
i,
1255 mcgraph()->machine()->ExtractF128(
static_cast<int32_t
>(
i)),
1258 edge.UpdateTo(input_128);
1260 TRACE(
"Replace Effect Edge from %d:%s, to %d:%s\n", useNode->
id(),
1261 useNode->
op()->mnemonic(), edge.to()->id(),
1262 edge.to()->op()->mnemonic());
1264 edge.UpdateTo(new_node);
1268 if (nodes[
i]->uses().empty()) nodes[
i]->
Kill();
1272 if (op == IrOpcode::kI8x16Shuffle &&
IsSplat(nodes)) {
1275 TRACE(
"Replace Effect Edge from %d:%s, to %d:%s\n", source->id(),
1276 source->op()->mnemonic(), new_node->
id(),
1277 new_node->
op()->mnemonic());
1281 TRACE(
"Remove Value Input of %d:%s\n", node0->
id(),
1282 node0->
op()->mnemonic());
1302 bool success =
false;
1304 TRACE(
"TryRevectorize %s\n", function);
1308 if (store_chains !=
nullptr) {
1311 TRACE(
"Successful revectorize %s\n", function);
1316 TRACE(
"Finish revectorize %s\n", function);
1324 std::vector<Node*> effect_uses;
1325 bool hasExternalValueUse =
false;
1326 for (
auto edge : src->use_edges()) {
1327 Node* use = edge.from();
1330 TRACE(
"Source node has external value dependence %d:%s\n",
1331 edge.from()->id(), edge.from()->op()->mnemonic());
1332 hasExternalValueUse =
true;
1335 effect_uses.push_back(use);
1340 if (!hasExternalValueUse) {
1343 for (
auto use : effect_uses) {
1344 TRACE(
"Replace Effect Edge for source node from %d:%s, to %d:%s\n",
1345 use->id(), use->op()->mnemonic(), effect->id(),
1346 effect->op()->mnemonic());
1361 if ((GetMemoryOffsetValue(node) %
kSimd128Size) != 0) {
1364 Node* address = GetNodeAddress(node);
1371 store_nodes = first_level_iter->second;
1373 auto second_level_iter = store_nodes->find(address);
1374 if (second_level_iter == store_nodes->end()) {
1378 second_level_iter->second.insert(node);
1384 TRACE(
"Enter %s\n", __func__);
1385 bool changed =
false;
1386 for (
auto chain_iter = store_chains->cbegin();
1387 chain_iter != store_chains->cend(); ++chain_iter) {
1388 if (chain_iter->second.size() >= 2 && chain_iter->second.size() % 2 == 0) {
1390 chain_iter->second.end(),
zone_);
1391 for (
auto it = store_chain.
begin(); it < store_chain.
end(); it = it + 2) {
1407 TRACE(
"Enter %s, root@ (#%d,#%d)\n", __func__, Stores[0]->
id(),
1409 if (!IsContinuousAccess(Stores)) {
1415 TRACE(
"Build tree failed!\n");
1441 if (!
v8_flags.trace_wasm_revectorize) {
1444 TRACE(
"Enter %s\n", __func__);
1445 for (
auto it = store_chains->cbegin(); it != store_chains->cend(); ++it) {
1446 if (it->second.size() > 0) {
1447 TRACE(
"address = #%d:%s \n", it->first->id(),
1448 it->first->op()->mnemonic());
1450 for (
auto node : it->second) {
1451 TRACE(
"#%d:%s, ", node->id(), node->op()->mnemonic());
static Isolate * TryGetCurrent()
void resize(size_t new_size)
static constexpr MachineType Simd256()
constexpr MachineRepresentation representation() const
void push_back(const T &value)
const Operator * Phi(MachineRepresentation representation, int value_input_count)
const Operator * LoopExitValue(MachineRepresentation rep)
Node * Int64Constant(int64_t value)
CommonOperatorBuilder * common() const
MachineOperatorBuilder * machine() const
const Operator * ProtectedLoad(LoadRepresentation rep)
const Operator * Load(LoadRepresentation rep)
const Operator * ProtectedStore(MachineRepresentation rep)
const Operator * Int64Add()
const Operator * Store(StoreRepresentation rep)
virtual Observation OnNodeCreated(const Node *node)
static void ReplaceEffectInput(Node *node, Node *effect, int index=0)
static Node * GetEffectInput(Node *node, int index=0)
static bool IsValueEdge(Edge edge)
static Node * GetValueInput(Node *node, int index)
static bool IsEffectEdge(Edge edge)
static void ReplaceValueInput(Node *node, Node *value, int index)
static int FirstControlIndex(Node *node)
static bool IsConstant(Node *node)
static bool IsPhi(Node *node)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
const Operator * op() const
void ReplaceInput(int index, Node *new_to)
Node * InputAt(int index) const
PackNode * GetOperand(size_t index)
void SetRevectorizedNode(Node *node)
void SetOperand(size_t index, PackNode *pnode)
ZoneVector< Node * > nodes_
const ZoneVector< Node * > & Nodes() const
Node * revectorized_node_
Node * RevectorizedNode() const
PackNode * GetPackNode(Node *node) const
void PrintStores(ZoneMap< Node *, StoreNodeSet > *store_chains)
MachineGraph * mcgraph() const
Revectorizer(Zone *zone, TFGraph *graph, MachineGraph *mcgraph, SourcePositionTable *source_positions)
std::unordered_set< Node * > sources_
MachineGraph *const mcgraph_
SourcePositionTable * source_positions_
bool ReduceStoreChains(ZoneMap< Node *, StoreNodeSet > *store_chains)
ZoneMap< Node *, ZoneMap< Node *, StoreNodeSet > * > group_of_stores_
void SetEffectInput(PackNode *pnode, int index, Node *&nput)
bool ReduceStoreChain(const ZoneVector< Node * > &Stores)
compiler::NodeObserver * node_observer_for_test_
bool TryRevectorize(const char *name)
Node * VectorizeTree(PackNode *pnode)
void SetMemoryOpInputs(base::SmallVector< Node *, 2 > &inputs, PackNode *pnode, int index)
ZoneSet< Node * > on_stack_
static constexpr size_t RecursionMaxDepth
void Print(const char *info)
bool IsSideEffectFreeLoad(const ZoneVector< Node * > &node_group)
Node * GetEarlySchedulePosition(Node *node)
PackNode * BuildTree(const ZoneVector< Node * > &roots)
PackNode * NewPackNodeAndRecurs(const ZoneVector< Node * > &node_group, int start_index, int count, unsigned depth)
PackNode * GetPackNode(Node *node)
PackNode * NewPackNode(const ZoneVector< Node * > &node_group)
PackNode * BuildTreeRec(const ZoneVector< Node * > &node_group, unsigned depth)
void TryReduceLoadChain(const ZoneVector< Node * > &loads)
bool CanBePacked(const ZoneVector< Node * > &node_group)
bool SameBasicBlock(Node *node0, Node *node1)
ZoneStack< ZoneVector< Node * > > stack_
void PushStack(const ZoneVector< Node * > &node_group)
ZoneUnorderedMap< Node *, PackNode * > node_to_packnode_
void ForEach(FunctionType callback)
bool AllOnStack(const ZoneVector< Node * > &node_group)
MachineRepresentation representation() const
WriteBarrierKind write_barrier_kind() const
ZoneVector< Node * > const & GetSimdStoreNodes()
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
static bool TryMatchSplat(const uint8_t *shuffle, int *index)
SourcePositionTable * source_positions
bool(* FunctionType)(const Operation &op, Zone *zone)
bool IsSplat(const T &node_group)
V8_EXPORT_PRIVATE LoadTransformParameters const & LoadTransformParametersOf(Operator const *) V8_WARN_UNUSED_RESULT
V8_EXPORT_PRIVATE S128ImmediateParameter const & S128ImmediateParameterOf(Operator const *op) V8_WARN_UNUSED_RESULT
StoreRepresentation const & StoreRepresentationOf(Operator const *op)
LoadRepresentation LoadRepresentationOf(Operator const *op)
T const & OpParameter(const Operator *op)
@ kProtectedByTrapHandler
MachineRepresentation LoopExitValueRepresentationOf(const Operator *const op)
MachineRepresentation PhiRepresentationOf(const Operator *const op)
ZoneSet< Node *, MemoryOffsetComparer > StoreNodeSet
constexpr int kSimd128Size
V8_EXPORT_PRIVATE FlagValues v8_flags
#define SIGN_EXTENSION_CONVERT_CASE(from, not_used, to)
#define SIMD_SIGN_EXTENSION_CONVERT_OP(V)
#define SIGN_EXTENSION_CASE(op_low, not_used1, not_used2)
#define SHIFT_CASE(from, to)
#define SPLAT_CASE(from, to)
#define SIMPLE_SIMD_OP(V)
#define CHECK_SIGN_EXTENSION_CASE(op_low, op_high, not_used)
#define SIMPLE_CASE(from, to)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
bool operator()(const Node *lhs, const Node *rhs) const