| 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 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 namespace compiler { | 13 namespace compiler { |
| 14 | 14 |
| 15 enum class OperandMode : uint32_t { | 15 enum class OperandMode : uint32_t { |
| 16 kNone = 0u, | 16 kNone = 0u, |
| 17 // Immediate mode | 17 // Immediate mode |
| 18 kShift32Imm = 1u << 0, | 18 kShift32Imm = 1u << 0, |
| 19 kShift64Imm = 1u << 1, | 19 kShift64Imm = 1u << 1, |
| 20 kInt32Imm = 1u << 2, | 20 kInt32Imm = 1u << 2, |
| 21 kInt32Imm_Negate = 1u << 3, | 21 kInt32Imm_Negate = 1u << 3, |
| 22 kUint32Imm = 1u << 4, | 22 kUint32Imm = 1u << 4, |
| 23 kInt20Imm = 1u << 5, | 23 kInt20Imm = 1u << 5, |
| 24 kUint12Imm = 1u << 6, |
| 24 // Instr format | 25 // Instr format |
| 25 kAllowRRR = 1u << 7, | 26 kAllowRRR = 1u << 7, |
| 26 kAllowRM = 1u << 8, | 27 kAllowRM = 1u << 8, |
| 27 kAllowRI = 1u << 9, | 28 kAllowRI = 1u << 9, |
| 28 kAllowRRI = 1u << 10, | 29 kAllowRRI = 1u << 10, |
| 29 kAllowRRM = 1u << 11, | 30 kAllowRRM = 1u << 11, |
| 30 // Useful combination | 31 // Useful combination |
| 31 kAllowImmediate = kAllowRI | kAllowRRI, | 32 kAllowImmediate = kAllowRI | kAllowRRI, |
| 32 kAllowMemoryOperand = kAllowRM | kAllowRRM, | 33 kAllowMemoryOperand = kAllowRM | kAllowRRM, |
| 33 kAllowDistinctOps = kAllowRRR | kAllowRRI | kAllowRRM, | 34 kAllowDistinctOps = kAllowRRR | kAllowRRI | kAllowRRM, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 explicit S390OperandGenerator(InstructionSelector* selector) | 77 explicit S390OperandGenerator(InstructionSelector* selector) |
| 77 : OperandGenerator(selector) {} | 78 : OperandGenerator(selector) {} |
| 78 | 79 |
| 79 InstructionOperand UseOperand(Node* node, OperandModes mode) { | 80 InstructionOperand UseOperand(Node* node, OperandModes mode) { |
| 80 if (CanBeImmediate(node, mode)) { | 81 if (CanBeImmediate(node, mode)) { |
| 81 return UseImmediate(node); | 82 return UseImmediate(node); |
| 82 } | 83 } |
| 83 return UseRegister(node); | 84 return UseRegister(node); |
| 84 } | 85 } |
| 85 | 86 |
| 87 InstructionOperand UseAnyExceptImmediate(Node* node) { |
| 88 if (NodeProperties::IsConstant(node)) |
| 89 return UseRegister(node); |
| 90 else |
| 91 return Use(node); |
| 92 } |
| 93 |
| 86 int64_t GetImmediate(Node* node) { | 94 int64_t GetImmediate(Node* node) { |
| 87 if (node->opcode() == IrOpcode::kInt32Constant) | 95 if (node->opcode() == IrOpcode::kInt32Constant) |
| 88 return OpParameter<int32_t>(node); | 96 return OpParameter<int32_t>(node); |
| 89 else if (node->opcode() == IrOpcode::kInt64Constant) | 97 else if (node->opcode() == IrOpcode::kInt64Constant) |
| 90 return OpParameter<int64_t>(node); | 98 return OpParameter<int64_t>(node); |
| 91 else | 99 else |
| 92 UNIMPLEMENTED(); | 100 UNIMPLEMENTED(); |
| 93 return 0L; | 101 return 0L; |
| 94 } | 102 } |
| 95 | 103 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 110 else if (mode & OperandMode::kShift64Imm) | 118 else if (mode & OperandMode::kShift64Imm) |
| 111 return 0 <= value && value < 64; | 119 return 0 <= value && value < 64; |
| 112 else if (mode & OperandMode::kInt32Imm) | 120 else if (mode & OperandMode::kInt32Imm) |
| 113 return is_int32(value); | 121 return is_int32(value); |
| 114 else if (mode & OperandMode::kInt32Imm_Negate) | 122 else if (mode & OperandMode::kInt32Imm_Negate) |
| 115 return is_int32(-value); | 123 return is_int32(-value); |
| 116 else if (mode & OperandMode::kUint32Imm) | 124 else if (mode & OperandMode::kUint32Imm) |
| 117 return is_uint32(value); | 125 return is_uint32(value); |
| 118 else if (mode & OperandMode::kInt20Imm) | 126 else if (mode & OperandMode::kInt20Imm) |
| 119 return is_int20(value); | 127 return is_int20(value); |
| 128 else if (mode & OperandMode::kUint12Imm) |
| 129 return is_uint12(value); |
| 120 else | 130 else |
| 121 return false; | 131 return false; |
| 122 } | 132 } |
| 123 | 133 |
| 134 bool CanBeMemoryOperand(InstructionCode opcode, Node* user, Node* input, |
| 135 int effect_level) { |
| 136 if (input->opcode() != IrOpcode::kLoad || |
| 137 !selector()->CanCover(user, input)) { |
| 138 return false; |
| 139 } |
| 140 |
| 141 if (effect_level != selector()->GetEffectLevel(input)) { |
| 142 return false; |
| 143 } |
| 144 |
| 145 MachineRepresentation rep = |
| 146 LoadRepresentationOf(input->op()).representation(); |
| 147 switch (opcode) { |
| 148 case kS390_Cmp64: |
| 149 case kS390_LoadAndTestWord64: |
| 150 return rep == MachineRepresentation::kWord64 || IsAnyTagged(rep); |
| 151 case kS390_LoadAndTestWord32: |
| 152 case kS390_Cmp32: |
| 153 return rep == MachineRepresentation::kWord32; |
| 154 default: |
| 155 break; |
| 156 } |
| 157 return false; |
| 158 } |
| 159 |
| 124 AddressingMode GenerateMemoryOperandInputs(Node* index, Node* base, | 160 AddressingMode GenerateMemoryOperandInputs(Node* index, Node* base, |
| 125 Node* displacement, | 161 Node* displacement, |
| 126 DisplacementMode displacement_mode, | 162 DisplacementMode displacement_mode, |
| 127 InstructionOperand inputs[], | 163 InstructionOperand inputs[], |
| 128 size_t* input_count) { | 164 size_t* input_count) { |
| 129 AddressingMode mode = kMode_MRI; | 165 AddressingMode mode = kMode_MRI; |
| 130 if (base != nullptr) { | 166 if (base != nullptr) { |
| 131 inputs[(*input_count)++] = UseRegister(base); | 167 inputs[(*input_count)++] = UseRegister(base); |
| 132 if (index != nullptr) { | 168 if (index != nullptr) { |
| 133 inputs[(*input_count)++] = UseRegister(index); | 169 inputs[(*input_count)++] = UseRegister(index); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 157 ? UseNegatedImmediate(displacement) | 193 ? UseNegatedImmediate(displacement) |
| 158 : UseImmediate(displacement); | 194 : UseImmediate(displacement); |
| 159 mode = kMode_MRI; | 195 mode = kMode_MRI; |
| 160 } else { | 196 } else { |
| 161 mode = kMode_MR; | 197 mode = kMode_MR; |
| 162 } | 198 } |
| 163 } | 199 } |
| 164 return mode; | 200 return mode; |
| 165 } | 201 } |
| 166 | 202 |
| 167 AddressingMode GetEffectiveAddressMemoryOperand(Node* operand, | 203 AddressingMode GetEffectiveAddressMemoryOperand( |
| 168 InstructionOperand inputs[], | 204 Node* operand, InstructionOperand inputs[], size_t* input_count, |
| 169 size_t* input_count) { | 205 OperandModes immediate_mode = OperandMode::kInt20Imm) { |
| 170 #if V8_TARGET_ARCH_S390X | 206 #if V8_TARGET_ARCH_S390X |
| 171 BaseWithIndexAndDisplacement64Matcher m(operand, | 207 BaseWithIndexAndDisplacement64Matcher m(operand, |
| 172 AddressOption::kAllowInputSwap); | 208 AddressOption::kAllowInputSwap); |
| 173 #else | 209 #else |
| 174 BaseWithIndexAndDisplacement32Matcher m(operand, | 210 BaseWithIndexAndDisplacement32Matcher m(operand, |
| 175 AddressOption::kAllowInputSwap); | 211 AddressOption::kAllowInputSwap); |
| 176 #endif | 212 #endif |
| 177 DCHECK(m.matches()); | 213 DCHECK(m.matches()); |
| 178 if ((m.displacement() == nullptr || | 214 if ((m.displacement() == nullptr || |
| 179 CanBeImmediate(m.displacement(), OperandMode::kInt20Imm))) { | 215 CanBeImmediate(m.displacement(), immediate_mode))) { |
| 180 DCHECK(m.scale() == 0); | 216 DCHECK(m.scale() == 0); |
| 181 return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(), | 217 return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(), |
| 182 m.displacement_mode(), inputs, | 218 m.displacement_mode(), inputs, |
| 183 input_count); | 219 input_count); |
| 184 } else { | 220 } else { |
| 185 inputs[(*input_count)++] = UseRegister(operand->InputAt(0)); | 221 inputs[(*input_count)++] = UseRegister(operand->InputAt(0)); |
| 186 inputs[(*input_count)++] = UseRegister(operand->InputAt(1)); | 222 inputs[(*input_count)++] = UseRegister(operand->InputAt(1)); |
| 187 return kMode_MRR; | 223 return kMode_MRR; |
| 188 } | 224 } |
| 189 } | 225 } |
| 190 | 226 |
| 191 bool CanBeBetterLeftOperand(Node* node) const { | 227 bool CanBeBetterLeftOperand(Node* node) const { |
| 192 return !selector()->IsLive(node); | 228 return !selector()->IsLive(node); |
| 193 } | 229 } |
| 194 | 230 |
| 195 MachineRepresentation GetRepresentation(Node* node) { | 231 MachineRepresentation GetRepresentation(Node* node) { |
| 196 return sequence()->GetRepresentation(selector()->GetVirtualRegister(node)); | 232 return sequence()->GetRepresentation(selector()->GetVirtualRegister(node)); |
| 197 } | 233 } |
| 198 | 234 |
| 199 bool Is64BitOperand(Node* node) { | 235 bool Is64BitOperand(Node* node) { |
| 200 return MachineRepresentation::kWord64 == GetRepresentation(node); | 236 return MachineRepresentation::kWord64 == GetRepresentation(node); |
| 201 } | 237 } |
| 202 }; | 238 }; |
| 203 | 239 |
| 204 namespace { | 240 namespace { |
| 205 | 241 |
| 242 bool S390OpcodeOnlySupport12BitDisp(ArchOpcode opcode) { |
| 243 switch (opcode) { |
| 244 case kS390_CmpFloat: |
| 245 case kS390_CmpDouble: |
| 246 return true; |
| 247 default: |
| 248 return false; |
| 249 } |
| 250 } |
| 251 |
| 252 bool S390OpcodeOnlySupport12BitDisp(InstructionCode op) { |
| 253 ArchOpcode opcode = ArchOpcodeField::decode(op); |
| 254 return S390OpcodeOnlySupport12BitDisp(opcode); |
| 255 } |
| 256 |
| 257 #define OpcodeImmMode(op) \ |
| 258 (S390OpcodeOnlySupport12BitDisp(op) ? OperandMode::kUint12Imm \ |
| 259 : OperandMode::kInt20Imm) |
| 260 |
| 206 ArchOpcode SelectLoadOpcode(Node* node) { | 261 ArchOpcode SelectLoadOpcode(Node* node) { |
| 207 NodeMatcher m(node); | 262 NodeMatcher m(node); |
| 208 DCHECK(m.IsLoad()); | 263 DCHECK(m.IsLoad()); |
| 209 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); | 264 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); |
| 210 ArchOpcode opcode = kArchNop; | 265 ArchOpcode opcode = kArchNop; |
| 211 switch (load_rep.representation()) { | 266 switch (load_rep.representation()) { |
| 212 case MachineRepresentation::kFloat32: | 267 case MachineRepresentation::kFloat32: |
| 213 opcode = kS390_LoadFloat32; | 268 opcode = kS390_LoadFloat32; |
| 214 break; | 269 break; |
| 215 case MachineRepresentation::kFloat64: | 270 case MachineRepresentation::kFloat64: |
| (...skipping 1518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1734 cont->frame_state()); | 1789 cont->frame_state()); |
| 1735 } else if (cont->IsSet()) { | 1790 } else if (cont->IsSet()) { |
| 1736 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); | 1791 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); |
| 1737 } else { | 1792 } else { |
| 1738 DCHECK(cont->IsTrap()); | 1793 DCHECK(cont->IsTrap()); |
| 1739 selector->Emit(opcode, g.NoOutput(), left, right, | 1794 selector->Emit(opcode, g.NoOutput(), left, right, |
| 1740 g.UseImmediate(cont->trap_id())); | 1795 g.UseImmediate(cont->trap_id())); |
| 1741 } | 1796 } |
| 1742 } | 1797 } |
| 1743 | 1798 |
| 1799 void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
| 1800 Node* value, InstructionCode opcode, |
| 1801 FlagsContinuation* cont); |
| 1802 |
| 1803 void VisitLoadAndTest(InstructionSelector* selector, InstructionCode opcode, |
| 1804 Node* node, Node* value, FlagsContinuation* cont, |
| 1805 bool discard_output = false); |
| 1806 |
| 1744 // Shared routine for multiple word compare operations. | 1807 // Shared routine for multiple word compare operations. |
| 1745 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1808 void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 1746 InstructionCode opcode, FlagsContinuation* cont, | 1809 InstructionCode opcode, FlagsContinuation* cont, |
| 1747 bool commutative, OperandModes immediate_mode) { | 1810 OperandModes immediate_mode) { |
| 1748 S390OperandGenerator g(selector); | 1811 S390OperandGenerator g(selector); |
| 1749 Node* left = node->InputAt(0); | 1812 Node* left = node->InputAt(0); |
| 1750 Node* right = node->InputAt(1); | 1813 Node* right = node->InputAt(1); |
| 1751 | 1814 |
| 1752 // Match immediates on left or right side of comparison. | 1815 DCHECK(IrOpcode::IsComparisonOpcode(node->opcode()) || |
| 1753 if (g.CanBeImmediate(right, immediate_mode)) { | 1816 node->opcode() == IrOpcode::kInt32Sub || |
| 1754 VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), | 1817 node->opcode() == IrOpcode::kInt64Sub); |
| 1755 cont); | 1818 |
| 1756 } else if (g.CanBeImmediate(left, immediate_mode)) { | 1819 InstructionOperand inputs[8]; |
| 1757 if (!commutative) cont->Commute(); | 1820 InstructionOperand outputs[1]; |
| 1758 VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), | 1821 size_t input_count = 0; |
| 1759 cont); | 1822 size_t output_count = 0; |
| 1823 |
| 1824 // If one of the two inputs is an immediate, make sure it's on the right, or |
| 1825 // if one of the two inputs is a memory operand, make sure it's on the left. |
| 1826 int effect_level = selector->GetEffectLevel(node); |
| 1827 if (cont->IsBranch()) { |
| 1828 effect_level = selector->GetEffectLevel( |
| 1829 cont->true_block()->PredecessorAt(0)->control_input()); |
| 1830 } |
| 1831 |
| 1832 if ((!g.CanBeImmediate(right, immediate_mode) && |
| 1833 g.CanBeImmediate(left, immediate_mode)) || |
| 1834 (!g.CanBeMemoryOperand(opcode, node, right, effect_level) && |
| 1835 g.CanBeMemoryOperand(opcode, node, left, effect_level))) { |
| 1836 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
| 1837 std::swap(left, right); |
| 1838 } |
| 1839 |
| 1840 // check if compare with 0 |
| 1841 if (g.CanBeImmediate(right, immediate_mode) && g.GetImmediate(right) == 0) { |
| 1842 DCHECK(opcode == kS390_Cmp32 || opcode == kS390_Cmp64); |
| 1843 ArchOpcode load_and_test = (opcode == kS390_Cmp32) |
| 1844 ? kS390_LoadAndTestWord32 |
| 1845 : kS390_LoadAndTestWord64; |
| 1846 return VisitLoadAndTest(selector, load_and_test, node, left, cont, true); |
| 1847 } |
| 1848 |
| 1849 inputs[input_count++] = g.UseRegister(left); |
| 1850 if (g.CanBeMemoryOperand(opcode, node, right, effect_level)) { |
| 1851 // generate memory operand |
| 1852 AddressingMode addressing_mode = g.GetEffectiveAddressMemoryOperand( |
| 1853 right, inputs, &input_count, OpcodeImmMode(opcode)); |
| 1854 opcode |= AddressingModeField::encode(addressing_mode); |
| 1855 } else if (g.CanBeImmediate(right, immediate_mode)) { |
| 1856 inputs[input_count++] = g.UseImmediate(right); |
| 1760 } else { | 1857 } else { |
| 1761 VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), | 1858 inputs[input_count++] = g.UseAnyExceptImmediate(right); |
| 1762 cont); | 1859 } |
| 1860 |
| 1861 opcode = cont->Encode(opcode); |
| 1862 if (cont->IsBranch()) { |
| 1863 inputs[input_count++] = g.Label(cont->true_block()); |
| 1864 inputs[input_count++] = g.Label(cont->false_block()); |
| 1865 } else if (cont->IsSet()) { |
| 1866 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
| 1867 } else if (cont->IsTrap()) { |
| 1868 inputs[input_count++] = g.UseImmediate(cont->trap_id()); |
| 1869 } else { |
| 1870 DCHECK(cont->IsDeoptimize()); |
| 1871 // nothing to do |
| 1872 } |
| 1873 |
| 1874 DCHECK(input_count <= 8 && output_count <= 1); |
| 1875 if (cont->IsDeoptimize()) { |
| 1876 selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs, |
| 1877 cont->reason(), cont->frame_state()); |
| 1878 } else { |
| 1879 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
| 1763 } | 1880 } |
| 1764 } | 1881 } |
| 1765 | 1882 |
| 1766 void VisitWord32Compare(InstructionSelector* selector, Node* node, | 1883 void VisitWord32Compare(InstructionSelector* selector, Node* node, |
| 1767 FlagsContinuation* cont) { | 1884 FlagsContinuation* cont) { |
| 1768 OperandModes mode = | 1885 OperandModes mode = |
| 1769 (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm); | 1886 (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm); |
| 1770 VisitWordCompare(selector, node, kS390_Cmp32, cont, false, mode); | 1887 VisitWordCompare(selector, node, kS390_Cmp32, cont, mode); |
| 1771 } | 1888 } |
| 1772 | 1889 |
| 1773 #if V8_TARGET_ARCH_S390X | 1890 #if V8_TARGET_ARCH_S390X |
| 1774 void VisitWord64Compare(InstructionSelector* selector, Node* node, | 1891 void VisitWord64Compare(InstructionSelector* selector, Node* node, |
| 1775 FlagsContinuation* cont) { | 1892 FlagsContinuation* cont) { |
| 1776 OperandModes mode = | 1893 OperandModes mode = |
| 1777 (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm); | 1894 (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm); |
| 1778 VisitWordCompare(selector, node, kS390_Cmp64, cont, false, mode); | 1895 VisitWordCompare(selector, node, kS390_Cmp64, cont, mode); |
| 1779 } | 1896 } |
| 1780 #endif | 1897 #endif |
| 1781 | 1898 |
| 1782 // Shared routine for multiple float32 compare operations. | 1899 // Shared routine for multiple float32 compare operations. |
| 1783 void VisitFloat32Compare(InstructionSelector* selector, Node* node, | 1900 void VisitFloat32Compare(InstructionSelector* selector, Node* node, |
| 1784 FlagsContinuation* cont) { | 1901 FlagsContinuation* cont) { |
| 1785 S390OperandGenerator g(selector); | 1902 VisitWordCompare(selector, node, kS390_CmpFloat, cont, OperandMode::kNone); |
| 1786 Node* left = node->InputAt(0); | |
| 1787 Node* right = node->InputAt(1); | |
| 1788 VisitCompare(selector, kS390_CmpFloat, g.UseRegister(left), | |
| 1789 g.UseRegister(right), cont); | |
| 1790 } | 1903 } |
| 1791 | 1904 |
| 1792 // Shared routine for multiple float64 compare operations. | 1905 // Shared routine for multiple float64 compare operations. |
| 1793 void VisitFloat64Compare(InstructionSelector* selector, Node* node, | 1906 void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
| 1794 FlagsContinuation* cont) { | 1907 FlagsContinuation* cont) { |
| 1908 VisitWordCompare(selector, node, kS390_CmpDouble, cont, OperandMode::kNone); |
| 1909 } |
| 1910 |
| 1911 void VisitTestUnderMask(InstructionSelector* selector, Node* node, |
| 1912 FlagsContinuation* cont) { |
| 1913 DCHECK(node->opcode() == IrOpcode::kWord32And || |
| 1914 node->opcode() == IrOpcode::kWord64And); |
| 1915 ArchOpcode opcode = |
| 1916 (node->opcode() == IrOpcode::kWord32And) ? kS390_Tst32 : kS390_Tst64; |
| 1795 S390OperandGenerator g(selector); | 1917 S390OperandGenerator g(selector); |
| 1796 Node* left = node->InputAt(0); | 1918 Node* left = node->InputAt(0); |
| 1797 Node* right = node->InputAt(1); | 1919 Node* right = node->InputAt(1); |
| 1798 VisitCompare(selector, kS390_CmpDouble, g.UseRegister(left), | 1920 if (!g.CanBeImmediate(right, OperandMode::kUint32Imm) && |
| 1799 g.UseRegister(right), cont); | 1921 g.CanBeImmediate(left, OperandMode::kUint32Imm)) { |
| 1922 std::swap(left, right); |
| 1923 } |
| 1924 VisitCompare(selector, opcode, g.UseRegister(left), |
| 1925 g.UseOperand(right, OperandMode::kUint32Imm), cont); |
| 1926 } |
| 1927 |
| 1928 void VisitLoadAndTest(InstructionSelector* selector, InstructionCode opcode, |
| 1929 Node* node, Node* value, FlagsContinuation* cont, |
| 1930 bool discard_output) { |
| 1931 static_assert(kS390_LoadAndTestFloat64 - kS390_LoadAndTestWord32 == 3, |
| 1932 "LoadAndTest Opcode shouldn't contain other opcodes."); |
| 1933 |
| 1934 // TODO(john.yan): Add support for Float32/Float64. |
| 1935 DCHECK(opcode >= kS390_LoadAndTestWord32 || |
| 1936 opcode <= kS390_LoadAndTestWord64); |
| 1937 |
| 1938 S390OperandGenerator g(selector); |
| 1939 InstructionOperand inputs[8]; |
| 1940 InstructionOperand outputs[2]; |
| 1941 size_t input_count = 0; |
| 1942 size_t output_count = 0; |
| 1943 bool use_value = false; |
| 1944 |
| 1945 int effect_level = selector->GetEffectLevel(node); |
| 1946 if (cont->IsBranch()) { |
| 1947 effect_level = selector->GetEffectLevel( |
| 1948 cont->true_block()->PredecessorAt(0)->control_input()); |
| 1949 } |
| 1950 |
| 1951 if (g.CanBeMemoryOperand(opcode, node, value, effect_level)) { |
| 1952 // generate memory operand |
| 1953 AddressingMode addressing_mode = |
| 1954 g.GetEffectiveAddressMemoryOperand(value, inputs, &input_count); |
| 1955 opcode |= AddressingModeField::encode(addressing_mode); |
| 1956 } else { |
| 1957 inputs[input_count++] = g.UseAnyExceptImmediate(value); |
| 1958 use_value = true; |
| 1959 } |
| 1960 |
| 1961 if (!discard_output && !use_value) { |
| 1962 outputs[output_count++] = g.DefineAsRegister(value); |
| 1963 } |
| 1964 |
| 1965 opcode = cont->Encode(opcode); |
| 1966 if (cont->IsBranch()) { |
| 1967 inputs[input_count++] = g.Label(cont->true_block()); |
| 1968 inputs[input_count++] = g.Label(cont->false_block()); |
| 1969 } else if (cont->IsSet()) { |
| 1970 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
| 1971 } else if (cont->IsTrap()) { |
| 1972 inputs[input_count++] = g.UseImmediate(cont->trap_id()); |
| 1973 } else { |
| 1974 DCHECK(cont->IsDeoptimize()); |
| 1975 // nothing to do |
| 1976 } |
| 1977 |
| 1978 DCHECK(input_count <= 8 && output_count <= 2); |
| 1979 opcode = cont->Encode(opcode); |
| 1980 if (cont->IsDeoptimize()) { |
| 1981 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, |
| 1982 cont->reason(), cont->frame_state()); |
| 1983 } else { |
| 1984 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
| 1985 } |
| 1800 } | 1986 } |
| 1801 | 1987 |
| 1802 // Shared routine for word comparisons against zero. | 1988 // Shared routine for word comparisons against zero. |
| 1803 void VisitWordCompareZero(InstructionSelector* selector, Node* user, | 1989 void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
| 1804 Node* value, InstructionCode opcode, | 1990 Node* value, InstructionCode opcode, |
| 1805 FlagsContinuation* cont) { | 1991 FlagsContinuation* cont) { |
| 1806 // Try to combine with comparisons against 0 by simply inverting the branch. | 1992 // Try to combine with comparisons against 0 by simply inverting the branch. |
| 1807 while (value->opcode() == IrOpcode::kWord32Equal && | 1993 while (value->opcode() == IrOpcode::kWord32Equal && |
| 1808 selector->CanCover(user, value)) { | 1994 selector->CanCover(user, value)) { |
| 1809 Int32BinopMatcher m(value); | 1995 Int32BinopMatcher m(value); |
| 1810 if (!m.right().Is(0)) break; | 1996 if (!m.right().Is(0)) break; |
| 1811 | 1997 |
| 1812 user = value; | 1998 user = value; |
| 1813 value = m.left().node(); | 1999 value = m.left().node(); |
| 1814 cont->Negate(); | 2000 cont->Negate(); |
| 1815 } | 2001 } |
| 1816 | 2002 |
| 2003 FlagsCondition fc = cont->condition(); |
| 1817 if (selector->CanCover(user, value)) { | 2004 if (selector->CanCover(user, value)) { |
| 1818 switch (value->opcode()) { | 2005 switch (value->opcode()) { |
| 1819 case IrOpcode::kWord32Equal: { | 2006 case IrOpcode::kWord32Equal: { |
| 1820 cont->OverwriteAndNegateIfEqual(kEqual); | 2007 cont->OverwriteAndNegateIfEqual(kEqual); |
| 1821 Int32BinopMatcher m(value); | 2008 Int32BinopMatcher m(value); |
| 1822 if (m.right().Is(0)) { | 2009 if (m.right().Is(0)) { |
| 1823 // Try to combine the branch with a comparison. | 2010 // Try to combine the branch with a comparison. |
| 1824 Node* const user = m.node(); | 2011 Node* const user = m.node(); |
| 1825 Node* const value = m.left().node(); | 2012 Node* const value = m.left().node(); |
| 1826 if (selector->CanCover(user, value)) { | 2013 if (selector->CanCover(user, value)) { |
| 1827 switch (value->opcode()) { | 2014 switch (value->opcode()) { |
| 1828 case IrOpcode::kInt32Sub: | 2015 case IrOpcode::kInt32Sub: |
| 1829 return VisitWord32Compare(selector, value, cont); | 2016 return VisitWord32Compare(selector, value, cont); |
| 1830 case IrOpcode::kWord32And: | 2017 case IrOpcode::kWord32And: |
| 1831 return VisitWordCompare(selector, value, kS390_Tst64, cont, | 2018 return VisitTestUnderMask(selector, value, cont); |
| 1832 true, OperandMode::kUint32Imm); | |
| 1833 default: | 2019 default: |
| 1834 break; | 2020 break; |
| 1835 } | 2021 } |
| 1836 } | 2022 } |
| 1837 } | 2023 } |
| 1838 return VisitWord32Compare(selector, value, cont); | 2024 return VisitWord32Compare(selector, value, cont); |
| 1839 } | 2025 } |
| 1840 case IrOpcode::kInt32LessThan: | 2026 case IrOpcode::kInt32LessThan: |
| 1841 cont->OverwriteAndNegateIfEqual(kSignedLessThan); | 2027 cont->OverwriteAndNegateIfEqual(kSignedLessThan); |
| 1842 return VisitWord32Compare(selector, value, cont); | 2028 return VisitWord32Compare(selector, value, cont); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1855 Int64BinopMatcher m(value); | 2041 Int64BinopMatcher m(value); |
| 1856 if (m.right().Is(0)) { | 2042 if (m.right().Is(0)) { |
| 1857 // Try to combine the branch with a comparison. | 2043 // Try to combine the branch with a comparison. |
| 1858 Node* const user = m.node(); | 2044 Node* const user = m.node(); |
| 1859 Node* const value = m.left().node(); | 2045 Node* const value = m.left().node(); |
| 1860 if (selector->CanCover(user, value)) { | 2046 if (selector->CanCover(user, value)) { |
| 1861 switch (value->opcode()) { | 2047 switch (value->opcode()) { |
| 1862 case IrOpcode::kInt64Sub: | 2048 case IrOpcode::kInt64Sub: |
| 1863 return VisitWord64Compare(selector, value, cont); | 2049 return VisitWord64Compare(selector, value, cont); |
| 1864 case IrOpcode::kWord64And: | 2050 case IrOpcode::kWord64And: |
| 1865 return VisitWordCompare(selector, value, kS390_Tst64, cont, | 2051 return VisitTestUnderMask(selector, value, cont); |
| 1866 true, OperandMode::kUint32Imm); | |
| 1867 default: | 2052 default: |
| 1868 break; | 2053 break; |
| 1869 } | 2054 } |
| 1870 } | 2055 } |
| 1871 } | 2056 } |
| 1872 return VisitWord64Compare(selector, value, cont); | 2057 return VisitWord64Compare(selector, value, cont); |
| 1873 } | 2058 } |
| 1874 case IrOpcode::kInt64LessThan: | 2059 case IrOpcode::kInt64LessThan: |
| 1875 cont->OverwriteAndNegateIfEqual(kSignedLessThan); | 2060 cont->OverwriteAndNegateIfEqual(kSignedLessThan); |
| 1876 return VisitWord64Compare(selector, value, cont); | 2061 return VisitWord64Compare(selector, value, cont); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1940 selector, node, kS390_Sub64, OperandMode::kInt32Imm_Negate, | 2125 selector, node, kS390_Sub64, OperandMode::kInt32Imm_Negate, |
| 1941 cont); | 2126 cont); |
| 1942 #endif | 2127 #endif |
| 1943 default: | 2128 default: |
| 1944 break; | 2129 break; |
| 1945 } | 2130 } |
| 1946 } | 2131 } |
| 1947 } | 2132 } |
| 1948 break; | 2133 break; |
| 1949 case IrOpcode::kInt32Sub: | 2134 case IrOpcode::kInt32Sub: |
| 1950 return VisitWord32Compare(selector, value, cont); | 2135 if (fc == kNotEqual || fc == kEqual) |
| 2136 return VisitWord32Compare(selector, value, cont); |
| 2137 break; |
| 1951 case IrOpcode::kWord32And: | 2138 case IrOpcode::kWord32And: |
| 1952 return VisitWordCompare(selector, value, kS390_Tst32, cont, true, | 2139 return VisitTestUnderMask(selector, value, cont); |
| 1953 OperandMode::kUint32Imm); | 2140 case IrOpcode::kLoad: { |
| 1954 // TODO(mbrandy): Handle? | 2141 LoadRepresentation load_rep = LoadRepresentationOf(value->op()); |
| 1955 // case IrOpcode::kInt32Add: | 2142 switch (load_rep.representation()) { |
| 1956 // case IrOpcode::kWord32Or: | 2143 case MachineRepresentation::kWord32: |
| 1957 // case IrOpcode::kWord32Xor: | 2144 if (opcode == kS390_LoadAndTestWord32) { |
| 1958 // case IrOpcode::kWord32Sar: | 2145 return VisitLoadAndTest(selector, opcode, user, value, cont); |
| 1959 // case IrOpcode::kWord32Shl: | 2146 } |
| 1960 // case IrOpcode::kWord32Shr: | 2147 default: |
| 1961 // case IrOpcode::kWord32Ror: | 2148 break; |
| 2149 } |
| 2150 break; |
| 2151 } |
| 2152 case IrOpcode::kInt32Add: |
| 2153 // can't handle overflow case. |
| 2154 break; |
| 2155 case IrOpcode::kWord32Or: |
| 2156 return VisitBin32op(selector, value, kS390_Or32, OrOperandMode, cont); |
| 2157 case IrOpcode::kWord32Xor: |
| 2158 return VisitBin32op(selector, value, kS390_Xor32, XorOperandMode, cont); |
| 2159 case IrOpcode::kWord32Sar: |
| 2160 case IrOpcode::kWord32Shl: |
| 2161 case IrOpcode::kWord32Shr: |
| 2162 case IrOpcode::kWord32Ror: |
| 2163 // doesn't generate cc, so ignore. |
| 2164 break; |
| 1962 #if V8_TARGET_ARCH_S390X | 2165 #if V8_TARGET_ARCH_S390X |
| 1963 case IrOpcode::kInt64Sub: | 2166 case IrOpcode::kInt64Sub: |
| 1964 return VisitWord64Compare(selector, value, cont); | 2167 if (fc == kNotEqual || fc == kEqual) |
| 2168 return VisitWord64Compare(selector, value, cont); |
| 2169 break; |
| 1965 case IrOpcode::kWord64And: | 2170 case IrOpcode::kWord64And: |
| 1966 return VisitWordCompare(selector, value, kS390_Tst64, cont, true, | 2171 return VisitTestUnderMask(selector, value, cont); |
| 1967 OperandMode::kUint32Imm); | 2172 case IrOpcode::kInt64Add: |
| 1968 // TODO(mbrandy): Handle? | 2173 // can't handle overflow case. |
| 1969 // case IrOpcode::kInt64Add: | 2174 break; |
| 1970 // case IrOpcode::kWord64Or: | 2175 case IrOpcode::kWord64Or: |
| 1971 // case IrOpcode::kWord64Xor: | 2176 // TODO(john.yan): need to handle |
| 1972 // case IrOpcode::kWord64Sar: | 2177 break; |
| 1973 // case IrOpcode::kWord64Shl: | 2178 case IrOpcode::kWord64Xor: |
| 1974 // case IrOpcode::kWord64Shr: | 2179 // TODO(john.yan): need to handle |
| 1975 // case IrOpcode::kWord64Ror: | 2180 break; |
| 2181 case IrOpcode::kWord64Sar: |
| 2182 case IrOpcode::kWord64Shl: |
| 2183 case IrOpcode::kWord64Shr: |
| 2184 case IrOpcode::kWord64Ror: |
| 2185 // doesn't generate cc, so ignore |
| 2186 break; |
| 1976 #endif | 2187 #endif |
| 1977 default: | 2188 default: |
| 1978 break; | 2189 break; |
| 1979 } | 2190 } |
| 1980 } | 2191 } |
| 1981 | 2192 |
| 1982 // Branch could not be combined with a compare, emit compare against 0. | 2193 // Branch could not be combined with a compare, emit LoadAndTest |
| 1983 S390OperandGenerator g(selector); | 2194 VisitLoadAndTest(selector, opcode, user, value, cont, true); |
| 1984 VisitCompare(selector, opcode, g.UseRegister(value), g.TempImmediate(0), | |
| 1985 cont); | |
| 1986 } | 2195 } |
| 1987 | 2196 |
| 1988 void VisitWord32CompareZero(InstructionSelector* selector, Node* user, | 2197 void VisitWord32CompareZero(InstructionSelector* selector, Node* user, |
| 1989 Node* value, FlagsContinuation* cont) { | 2198 Node* value, FlagsContinuation* cont) { |
| 1990 VisitWordCompareZero(selector, user, value, kS390_Cmp32, cont); | 2199 VisitWordCompareZero(selector, user, value, kS390_LoadAndTestWord32, cont); |
| 1991 } | 2200 } |
| 1992 | 2201 |
| 1993 #if V8_TARGET_ARCH_S390X | 2202 #if V8_TARGET_ARCH_S390X |
| 1994 void VisitWord64CompareZero(InstructionSelector* selector, Node* user, | 2203 void VisitWord64CompareZero(InstructionSelector* selector, Node* user, |
| 1995 Node* value, FlagsContinuation* cont) { | 2204 Node* value, FlagsContinuation* cont) { |
| 1996 VisitWordCompareZero(selector, user, value, kS390_Cmp64, cont); | 2205 VisitWordCompareZero(selector, user, value, kS390_LoadAndTestWord64, cont); |
| 1997 } | 2206 } |
| 1998 #endif | 2207 #endif |
| 1999 | 2208 |
| 2000 } // namespace | 2209 } // namespace |
| 2001 | 2210 |
| 2002 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, | 2211 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 2003 BasicBlock* fbranch) { | 2212 BasicBlock* fbranch) { |
| 2004 FlagsContinuation cont(kNotEqual, tbranch, fbranch); | 2213 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 2005 VisitWord32CompareZero(this, branch, branch->InputAt(0), &cont); | 2214 VisitWord32CompareZero(this, branch, branch->InputAt(0), &cont); |
| 2006 } | 2215 } |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2317 // static | 2526 // static |
| 2318 MachineOperatorBuilder::AlignmentRequirements | 2527 MachineOperatorBuilder::AlignmentRequirements |
| 2319 InstructionSelector::AlignmentRequirements() { | 2528 InstructionSelector::AlignmentRequirements() { |
| 2320 return MachineOperatorBuilder::AlignmentRequirements:: | 2529 return MachineOperatorBuilder::AlignmentRequirements:: |
| 2321 FullUnalignedAccessSupport(); | 2530 FullUnalignedAccessSupport(); |
| 2322 } | 2531 } |
| 2323 | 2532 |
| 2324 } // namespace compiler | 2533 } // namespace compiler |
| 2325 } // namespace internal | 2534 } // namespace internal |
| 2326 } // namespace v8 | 2535 } // namespace v8 |
| OLD | NEW |