| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/adapters.h" | 5 #include "src/base/adapters.h" |
| 6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
| 7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
| 8 #include "src/compiler/node-properties.h" | 8 #include "src/compiler/node-properties.h" |
| 9 #include "src/s390/frames-s390.h" | 9 #include "src/s390/frames-s390.h" |
| 10 | 10 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 explicit S390OperandGenerator(InstructionSelector* selector) | 28 explicit S390OperandGenerator(InstructionSelector* selector) |
| 29 : OperandGenerator(selector) {} | 29 : OperandGenerator(selector) {} |
| 30 | 30 |
| 31 InstructionOperand UseOperand(Node* node, ImmediateMode mode) { | 31 InstructionOperand UseOperand(Node* node, ImmediateMode mode) { |
| 32 if (CanBeImmediate(node, mode)) { | 32 if (CanBeImmediate(node, mode)) { |
| 33 return UseImmediate(node); | 33 return UseImmediate(node); |
| 34 } | 34 } |
| 35 return UseRegister(node); | 35 return UseRegister(node); |
| 36 } | 36 } |
| 37 | 37 |
| 38 int64_t GetImmediate(Node* node) { |
| 39 if (node->opcode() == IrOpcode::kInt32Constant) |
| 40 return OpParameter<int32_t>(node); |
| 41 else if (node->opcode() == IrOpcode::kInt64Constant) |
| 42 return OpParameter<int64_t>(node); |
| 43 else |
| 44 UNIMPLEMENTED(); |
| 45 return 0L; |
| 46 } |
| 47 |
| 38 bool CanBeImmediate(Node* node, ImmediateMode mode) { | 48 bool CanBeImmediate(Node* node, ImmediateMode mode) { |
| 39 int64_t value; | 49 int64_t value; |
| 40 if (node->opcode() == IrOpcode::kInt32Constant) | 50 if (node->opcode() == IrOpcode::kInt32Constant) |
| 41 value = OpParameter<int32_t>(node); | 51 value = OpParameter<int32_t>(node); |
| 42 else if (node->opcode() == IrOpcode::kInt64Constant) | 52 else if (node->opcode() == IrOpcode::kInt64Constant) |
| 43 value = OpParameter<int64_t>(node); | 53 value = OpParameter<int64_t>(node); |
| 44 else | 54 else |
| 45 return false; | 55 return false; |
| 46 return CanBeImmediate(value, mode); | 56 return CanBeImmediate(value, mode); |
| 47 } | 57 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 DCHECK(m.scale() == 0); | 135 DCHECK(m.scale() == 0); |
| 126 return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(), | 136 return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(), |
| 127 m.displacement_mode(), inputs, | 137 m.displacement_mode(), inputs, |
| 128 input_count); | 138 input_count); |
| 129 } else { | 139 } else { |
| 130 inputs[(*input_count)++] = UseRegister(operand->InputAt(0)); | 140 inputs[(*input_count)++] = UseRegister(operand->InputAt(0)); |
| 131 inputs[(*input_count)++] = UseRegister(operand->InputAt(1)); | 141 inputs[(*input_count)++] = UseRegister(operand->InputAt(1)); |
| 132 return kMode_MRR; | 142 return kMode_MRR; |
| 133 } | 143 } |
| 134 } | 144 } |
| 145 |
| 146 bool CanBeBetterLeftOperand(Node* node) const { |
| 147 return !selector()->IsLive(node); |
| 148 } |
| 149 |
| 150 MachineRepresentation GetRepresentation(Node* node) { |
| 151 return sequence()->GetRepresentation(selector()->GetVirtualRegister(node)); |
| 152 } |
| 153 |
| 154 bool Is64BitOperand(Node* node) { |
| 155 return MachineRepresentation::kWord64 == GetRepresentation(node); |
| 156 } |
| 135 }; | 157 }; |
| 136 | 158 |
| 137 namespace { | 159 namespace { |
| 138 | 160 |
| 139 void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { | 161 void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { |
| 140 S390OperandGenerator g(selector); | 162 S390OperandGenerator g(selector); |
| 141 selector->Emit(opcode, g.DefineAsRegister(node), | 163 selector->Emit(opcode, g.DefineAsRegister(node), |
| 142 g.UseRegister(node->InputAt(0))); | 164 g.UseRegister(node->InputAt(0))); |
| 143 } | 165 } |
| 144 | 166 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 175 } | 197 } |
| 176 #endif | 198 #endif |
| 177 | 199 |
| 178 // Shared routine for multiple binary operations. | 200 // Shared routine for multiple binary operations. |
| 179 template <typename Matcher> | 201 template <typename Matcher> |
| 180 void VisitBinop(InstructionSelector* selector, Node* node, | 202 void VisitBinop(InstructionSelector* selector, Node* node, |
| 181 InstructionCode opcode, ImmediateMode operand_mode, | 203 InstructionCode opcode, ImmediateMode operand_mode, |
| 182 FlagsContinuation* cont) { | 204 FlagsContinuation* cont) { |
| 183 S390OperandGenerator g(selector); | 205 S390OperandGenerator g(selector); |
| 184 Matcher m(node); | 206 Matcher m(node); |
| 207 Node* left = m.left().node(); |
| 208 Node* right = m.right().node(); |
| 185 InstructionOperand inputs[4]; | 209 InstructionOperand inputs[4]; |
| 186 size_t input_count = 0; | 210 size_t input_count = 0; |
| 187 InstructionOperand outputs[2]; | 211 InstructionOperand outputs[2]; |
| 188 size_t output_count = 0; | 212 size_t output_count = 0; |
| 189 | 213 |
| 190 inputs[input_count++] = g.UseRegister(m.left().node()); | 214 // TODO(turbofan): match complex addressing modes. |
| 191 inputs[input_count++] = g.UseOperand(m.right().node(), operand_mode); | 215 if (left == right) { |
| 216 // If both inputs refer to the same operand, enforce allocating a register |
| 217 // for both of them to ensure that we don't end up generating code like |
| 218 // this: |
| 219 // |
| 220 // mov rax, [rbp-0x10] |
| 221 // add rax, [rbp-0x10] |
| 222 // jo label |
| 223 InstructionOperand const input = g.UseRegister(left); |
| 224 inputs[input_count++] = input; |
| 225 inputs[input_count++] = input; |
| 226 } else if (g.CanBeImmediate(right, operand_mode)) { |
| 227 inputs[input_count++] = g.UseRegister(left); |
| 228 inputs[input_count++] = g.UseImmediate(right); |
| 229 } else { |
| 230 if (node->op()->HasProperty(Operator::kCommutative) && |
| 231 g.CanBeBetterLeftOperand(right)) { |
| 232 std::swap(left, right); |
| 233 } |
| 234 inputs[input_count++] = g.UseRegister(left); |
| 235 inputs[input_count++] = g.UseRegister(right); |
| 236 } |
| 192 | 237 |
| 193 if (cont->IsBranch()) { | 238 if (cont->IsBranch()) { |
| 194 inputs[input_count++] = g.Label(cont->true_block()); | 239 inputs[input_count++] = g.Label(cont->true_block()); |
| 195 inputs[input_count++] = g.Label(cont->false_block()); | 240 inputs[input_count++] = g.Label(cont->false_block()); |
| 196 } | 241 } |
| 197 | 242 |
| 198 if (cont->IsDeoptimize()) { | 243 if (cont->IsDeoptimize()) { |
| 199 // If we can deoptimize as a result of the binop, we need to make sure that | 244 // If we can deoptimize as a result of the binop, we need to make sure that |
| 200 // the deopt inputs are not overwritten by the binop result. One way | 245 // the deopt inputs are not overwritten by the binop result. One way |
| 201 // to achieve that is to declare the output register as same-as-first. | 246 // to achieve that is to declare the output register as same-as-first. |
| (...skipping 793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 995 { | 1040 { |
| 996 InstructionOperand shift_31 = g.UseImmediate(31); | 1041 InstructionOperand shift_31 = g.UseImmediate(31); |
| 997 InstructionOperand outputs[] = {temp_operand}; | 1042 InstructionOperand outputs[] = {temp_operand}; |
| 998 InstructionOperand inputs[] = {result_operand, shift_31}; | 1043 InstructionOperand inputs[] = {result_operand, shift_31}; |
| 999 selector->Emit(kS390_ShiftRightArith32, 1, outputs, 2, inputs); | 1044 selector->Emit(kS390_ShiftRightArith32, 1, outputs, 2, inputs); |
| 1000 } | 1045 } |
| 1001 | 1046 |
| 1002 VisitCompare(selector, kS390_Cmp32, high32_operand, temp_operand, cont); | 1047 VisitCompare(selector, kS390_Cmp32, high32_operand, temp_operand, cont); |
| 1003 } | 1048 } |
| 1004 | 1049 |
| 1050 void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
| 1051 S390OperandGenerator g(selector); |
| 1052 Int32BinopMatcher m(node); |
| 1053 Node* left = m.left().node(); |
| 1054 Node* right = m.right().node(); |
| 1055 if (g.CanBeImmediate(right, kInt32Imm)) { |
| 1056 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 1057 g.UseImmediate(right)); |
| 1058 } else { |
| 1059 if (g.CanBeBetterLeftOperand(right)) { |
| 1060 std::swap(left, right); |
| 1061 } |
| 1062 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 1063 g.Use(right)); |
| 1064 } |
| 1065 } |
| 1066 |
| 1005 } // namespace | 1067 } // namespace |
| 1006 | 1068 |
| 1069 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { |
| 1070 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
| 1071 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); |
| 1072 return EmitInt32MulWithOverflow(this, node, &cont); |
| 1073 } |
| 1074 VisitMul(this, node, kS390_Mul32); |
| 1075 // FlagsContinuation cont; |
| 1076 // EmitInt32MulWithOverflow(this, node, &cont); |
| 1077 } |
| 1078 |
| 1007 void InstructionSelector::VisitInt32Mul(Node* node) { | 1079 void InstructionSelector::VisitInt32Mul(Node* node) { |
| 1008 VisitRRR(this, kS390_Mul32, node); | 1080 S390OperandGenerator g(this); |
| 1081 Int32BinopMatcher m(node); |
| 1082 Node* left = m.left().node(); |
| 1083 Node* right = m.right().node(); |
| 1084 if (g.CanBeImmediate(right, kInt32Imm) && |
| 1085 base::bits::IsPowerOfTwo32(g.GetImmediate(right))) { |
| 1086 int power = 31 - base::bits::CountLeadingZeros32(g.GetImmediate(right)); |
| 1087 Emit(kS390_ShiftLeft32, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 1088 g.UseImmediate(power)); |
| 1089 return; |
| 1090 } |
| 1091 VisitMul(this, node, kS390_Mul32); |
| 1009 } | 1092 } |
| 1010 | 1093 |
| 1011 #if V8_TARGET_ARCH_S390X | 1094 #if V8_TARGET_ARCH_S390X |
| 1012 void InstructionSelector::VisitInt64Mul(Node* node) { | 1095 void InstructionSelector::VisitInt64Mul(Node* node) { |
| 1013 VisitRRR(this, kS390_Mul64, node); | 1096 S390OperandGenerator g(this); |
| 1097 Int64BinopMatcher m(node); |
| 1098 Node* left = m.left().node(); |
| 1099 Node* right = m.right().node(); |
| 1100 if (g.CanBeImmediate(right, kInt32Imm) && |
| 1101 base::bits::IsPowerOfTwo64(g.GetImmediate(right))) { |
| 1102 int power = 31 - base::bits::CountLeadingZeros64(g.GetImmediate(right)); |
| 1103 Emit(kS390_ShiftLeft64, g.DefineSameAsFirst(node), g.UseRegister(left), |
| 1104 g.UseImmediate(power)); |
| 1105 return; |
| 1106 } |
| 1107 VisitMul(this, node, kS390_Mul64); |
| 1014 } | 1108 } |
| 1015 #endif | 1109 #endif |
| 1016 | 1110 |
| 1017 void InstructionSelector::VisitInt32MulHigh(Node* node) { | 1111 void InstructionSelector::VisitInt32MulHigh(Node* node) { |
| 1018 S390OperandGenerator g(this); | 1112 S390OperandGenerator g(this); |
| 1019 Emit(kS390_MulHigh32, g.DefineAsRegister(node), | 1113 Int32BinopMatcher m(node); |
| 1020 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); | 1114 Node* left = m.left().node(); |
| 1115 Node* right = m.right().node(); |
| 1116 if (g.CanBeBetterLeftOperand(right)) { |
| 1117 std::swap(left, right); |
| 1118 } |
| 1119 Emit(kS390_MulHigh32, g.DefineAsRegister(node), g.UseRegister(left), |
| 1120 g.Use(right)); |
| 1021 } | 1121 } |
| 1022 | 1122 |
| 1023 void InstructionSelector::VisitUint32MulHigh(Node* node) { | 1123 void InstructionSelector::VisitUint32MulHigh(Node* node) { |
| 1024 S390OperandGenerator g(this); | 1124 S390OperandGenerator g(this); |
| 1025 Emit(kS390_MulHighU32, g.DefineAsRegister(node), | 1125 Int32BinopMatcher m(node); |
| 1026 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); | 1126 Node* left = m.left().node(); |
| 1127 Node* right = m.right().node(); |
| 1128 if (g.CanBeBetterLeftOperand(right)) { |
| 1129 std::swap(left, right); |
| 1130 } |
| 1131 Emit(kS390_MulHighU32, g.DefineAsRegister(node), g.UseRegister(left), |
| 1132 g.Use(right)); |
| 1027 } | 1133 } |
| 1028 | 1134 |
| 1029 void InstructionSelector::VisitInt32Div(Node* node) { | 1135 void InstructionSelector::VisitInt32Div(Node* node) { |
| 1030 VisitRRR(this, kS390_Div32, node); | 1136 VisitRRR(this, kS390_Div32, node); |
| 1031 } | 1137 } |
| 1032 | 1138 |
| 1033 #if V8_TARGET_ARCH_S390X | 1139 #if V8_TARGET_ARCH_S390X |
| 1034 void InstructionSelector::VisitInt64Div(Node* node) { | 1140 void InstructionSelector::VisitInt64Div(Node* node) { |
| 1035 VisitRRR(this, kS390_Div64, node); | 1141 VisitRRR(this, kS390_Div64, node); |
| 1036 } | 1142 } |
| (...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1714 VisitWord64Compare(this, node, &cont); | 1820 VisitWord64Compare(this, node, &cont); |
| 1715 } | 1821 } |
| 1716 | 1822 |
| 1717 void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) { | 1823 void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) { |
| 1718 FlagsContinuation cont = | 1824 FlagsContinuation cont = |
| 1719 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); | 1825 FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); |
| 1720 VisitWord64Compare(this, node, &cont); | 1826 VisitWord64Compare(this, node, &cont); |
| 1721 } | 1827 } |
| 1722 #endif | 1828 #endif |
| 1723 | 1829 |
| 1724 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { | |
| 1725 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | |
| 1726 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); | |
| 1727 return EmitInt32MulWithOverflow(this, node, &cont); | |
| 1728 } | |
| 1729 FlagsContinuation cont; | |
| 1730 EmitInt32MulWithOverflow(this, node, &cont); | |
| 1731 } | |
| 1732 | |
| 1733 void InstructionSelector::VisitFloat32Equal(Node* node) { | 1830 void InstructionSelector::VisitFloat32Equal(Node* node) { |
| 1734 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); | 1831 FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); |
| 1735 VisitFloat32Compare(this, node, &cont); | 1832 VisitFloat32Compare(this, node, &cont); |
| 1736 } | 1833 } |
| 1737 | 1834 |
| 1738 void InstructionSelector::VisitFloat32LessThan(Node* node) { | 1835 void InstructionSelector::VisitFloat32LessThan(Node* node) { |
| 1739 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); | 1836 FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); |
| 1740 VisitFloat32Compare(this, node, &cont); | 1837 VisitFloat32Compare(this, node, &cont); |
| 1741 } | 1838 } |
| 1742 | 1839 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1921 // static | 2018 // static |
| 1922 MachineOperatorBuilder::AlignmentRequirements | 2019 MachineOperatorBuilder::AlignmentRequirements |
| 1923 InstructionSelector::AlignmentRequirements() { | 2020 InstructionSelector::AlignmentRequirements() { |
| 1924 return MachineOperatorBuilder::AlignmentRequirements:: | 2021 return MachineOperatorBuilder::AlignmentRequirements:: |
| 1925 FullUnalignedAccessSupport(); | 2022 FullUnalignedAccessSupport(); |
| 1926 } | 2023 } |
| 1927 | 2024 |
| 1928 } // namespace compiler | 2025 } // namespace compiler |
| 1929 } // namespace internal | 2026 } // namespace internal |
| 1930 } // namespace v8 | 2027 } // namespace v8 |
| OLD | NEW |