OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/compiler/code-generator.h" | 5 #include "src/compiler/code-generator.h" |
6 #include "src/compiler/code-generator-impl.h" | 6 #include "src/compiler/code-generator-impl.h" |
7 #include "src/compiler/gap-resolver.h" | 7 #include "src/compiler/gap-resolver.h" |
8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/osr.h" | 9 #include "src/compiler/osr.h" |
10 #include "src/mips/macro-assembler-mips.h" | 10 #include "src/mips/macro-assembler-mips.h" |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 }; | 194 }; |
195 | 195 |
196 | 196 |
197 class OutOfLineCeil final : public OutOfLineRound { | 197 class OutOfLineCeil final : public OutOfLineRound { |
198 public: | 198 public: |
199 OutOfLineCeil(CodeGenerator* gen, DoubleRegister result) | 199 OutOfLineCeil(CodeGenerator* gen, DoubleRegister result) |
200 : OutOfLineRound(gen, result) {} | 200 : OutOfLineRound(gen, result) {} |
201 }; | 201 }; |
202 | 202 |
203 | 203 |
204 Condition FlagsConditionToConditionCmp(FlagsCondition condition) { | 204 Condition FlagsConditionToConditionCmp(bool& predicate, |
| 205 FlagsCondition condition) { |
205 switch (condition) { | 206 switch (condition) { |
206 case kEqual: | 207 case kEqual: |
| 208 predicate = true; |
207 return eq; | 209 return eq; |
208 case kNotEqual: | 210 case kNotEqual: |
| 211 predicate = false; |
209 return ne; | 212 return ne; |
210 case kSignedLessThan: | 213 case kSignedLessThan: |
| 214 predicate = true; |
211 return lt; | 215 return lt; |
212 case kSignedGreaterThanOrEqual: | 216 case kSignedGreaterThanOrEqual: |
| 217 predicate = false; |
213 return ge; | 218 return ge; |
214 case kSignedLessThanOrEqual: | 219 case kSignedLessThanOrEqual: |
| 220 predicate = false; |
215 return le; | 221 return le; |
216 case kSignedGreaterThan: | 222 case kSignedGreaterThan: |
| 223 predicate = true; |
217 return gt; | 224 return gt; |
218 case kUnsignedLessThan: | 225 case kUnsignedLessThan: |
| 226 predicate = true; |
219 return lo; | 227 return lo; |
220 case kUnsignedGreaterThanOrEqual: | 228 case kUnsignedGreaterThanOrEqual: |
| 229 predicate = false; |
221 return hs; | 230 return hs; |
222 case kUnsignedLessThanOrEqual: | 231 case kUnsignedLessThanOrEqual: |
| 232 predicate = false; |
223 return ls; | 233 return ls; |
224 case kUnsignedGreaterThan: | 234 case kUnsignedGreaterThan: |
| 235 predicate = true; |
225 return hi; | 236 return hi; |
226 case kUnorderedEqual: | 237 case kUnorderedEqual: |
227 case kUnorderedNotEqual: | 238 case kUnorderedNotEqual: |
| 239 predicate = true; |
228 break; | 240 break; |
229 default: | 241 default: |
| 242 predicate = true; |
230 break; | 243 break; |
231 } | 244 } |
232 UNREACHABLE(); | 245 UNREACHABLE(); |
233 return kNoCondition; | 246 return kNoCondition; |
234 } | 247 } |
235 | 248 |
236 | 249 |
237 Condition FlagsConditionToConditionTst(FlagsCondition condition) { | 250 Condition FlagsConditionToConditionTst(bool& predicate, |
| 251 FlagsCondition condition) { |
238 switch (condition) { | 252 switch (condition) { |
239 case kNotEqual: | 253 case kNotEqual: |
| 254 predicate = false; |
240 return ne; | 255 return ne; |
241 case kEqual: | 256 case kEqual: |
| 257 predicate = true; |
242 return eq; | 258 return eq; |
243 default: | 259 default: |
| 260 predicate = true; |
244 break; | 261 break; |
245 } | 262 } |
246 UNREACHABLE(); | 263 UNREACHABLE(); |
247 return kNoCondition; | 264 return kNoCondition; |
248 } | 265 } |
249 | 266 |
250 | 267 |
251 Condition FlagsConditionToConditionOvf(FlagsCondition condition) { | 268 Condition FlagsConditionToConditionOvf(bool& predicate, |
| 269 FlagsCondition condition) { |
252 switch (condition) { | 270 switch (condition) { |
253 case kOverflow: | 271 case kOverflow: |
| 272 predicate = true; |
254 return ne; | 273 return ne; |
255 case kNotOverflow: | 274 case kNotOverflow: |
| 275 predicate = false; |
256 return eq; | 276 return eq; |
257 default: | 277 default: |
| 278 predicate = true; |
258 break; | 279 break; |
259 } | 280 } |
260 UNREACHABLE(); | 281 UNREACHABLE(); |
261 return kNoCondition; | 282 return kNoCondition; |
262 } | 283 } |
263 | 284 |
264 | 285 |
265 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, | 286 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, |
266 FlagsCondition condition) { | 287 FlagsCondition condition) { |
267 switch (condition) { | 288 switch (condition) { |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 return false; | 989 return false; |
969 } | 990 } |
970 | 991 |
971 | 992 |
972 // Assembles branches after an instruction. | 993 // Assembles branches after an instruction. |
973 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { | 994 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { |
974 MipsOperandConverter i(this, instr); | 995 MipsOperandConverter i(this, instr); |
975 Label* tlabel = branch->true_label; | 996 Label* tlabel = branch->true_label; |
976 Label* flabel = branch->false_label; | 997 Label* flabel = branch->false_label; |
977 Condition cc = kNoCondition; | 998 Condition cc = kNoCondition; |
978 | 999 bool predicate; |
979 // MIPS does not have condition code flags, so compare and branch are | 1000 // MIPS does not have condition code flags, so compare and branch are |
980 // implemented differently than on the other arch's. The compare operations | 1001 // implemented differently than on the other arch's. The compare operations |
981 // emit mips psuedo-instructions, which are handled here by branch | 1002 // emit mips psuedo-instructions, which are handled here by branch |
982 // instructions that do the actual comparison. Essential that the input | 1003 // instructions that do the actual comparison. Essential that the input |
983 // registers to compare pseudo-op are not modified before this branch op, as | 1004 // registers to compare pseudo-op are not modified before this branch op, as |
984 // they are tested here. | 1005 // they are tested here. |
985 | 1006 |
986 if (instr->arch_opcode() == kMips64Tst) { | 1007 if (instr->arch_opcode() == kMips64Tst) { |
987 cc = FlagsConditionToConditionTst(branch->condition); | 1008 cc = FlagsConditionToConditionTst(predicate, branch->condition); |
988 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 1009 __ And(at, i.InputRegister(0), i.InputOperand(1)); |
989 __ Branch(tlabel, cc, at, Operand(zero_reg)); | 1010 __ Branch(tlabel, cc, at, Operand(zero_reg)); |
990 } else if (instr->arch_opcode() == kMips64Dadd || | 1011 } else if (instr->arch_opcode() == kMips64Dadd || |
991 instr->arch_opcode() == kMips64Dsub) { | 1012 instr->arch_opcode() == kMips64Dsub) { |
992 cc = FlagsConditionToConditionOvf(branch->condition); | 1013 cc = FlagsConditionToConditionOvf(predicate, branch->condition); |
993 __ dsra32(kScratchReg, i.OutputRegister(), 0); | 1014 __ dsra32(kScratchReg, i.OutputRegister(), 0); |
994 __ sra(at, i.OutputRegister(), 31); | 1015 __ sra(at, i.OutputRegister(), 31); |
995 __ Branch(tlabel, cc, at, Operand(kScratchReg)); | 1016 __ Branch(tlabel, cc, at, Operand(kScratchReg)); |
996 } else if (instr->arch_opcode() == kMips64Cmp) { | 1017 } else if (instr->arch_opcode() == kMips64Cmp) { |
997 cc = FlagsConditionToConditionCmp(branch->condition); | 1018 cc = FlagsConditionToConditionCmp(predicate, branch->condition); |
998 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); | 1019 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); |
999 } else if (instr->arch_opcode() == kMips64CmpS) { | 1020 } else if (instr->arch_opcode() == kMips64CmpS) { |
1000 if (!convertCondition(branch->condition, cc)) { | 1021 if (!convertCondition(branch->condition, cc)) { |
1001 UNSUPPORTED_COND(kMips64CmpS, branch->condition); | 1022 UNSUPPORTED_COND(kMips64CmpS, branch->condition); |
1002 } | 1023 } |
1003 __ BranchF32(tlabel, NULL, cc, i.InputSingleRegister(0), | 1024 __ BranchF32(tlabel, NULL, cc, i.InputSingleRegister(0), |
1004 i.InputSingleRegister(1)); | 1025 i.InputSingleRegister(1)); |
1005 } else if (instr->arch_opcode() == kMips64CmpD) { | 1026 } else if (instr->arch_opcode() == kMips64CmpD) { |
1006 if (!convertCondition(branch->condition, cc)) { | 1027 if (!convertCondition(branch->condition, cc)) { |
1007 UNSUPPORTED_COND(kMips64CmpD, branch->condition); | 1028 UNSUPPORTED_COND(kMips64CmpD, branch->condition); |
(...skipping 19 matching lines...) Expand all Loading... |
1027 FlagsCondition condition) { | 1048 FlagsCondition condition) { |
1028 MipsOperandConverter i(this, instr); | 1049 MipsOperandConverter i(this, instr); |
1029 Label done; | 1050 Label done; |
1030 | 1051 |
1031 // Materialize a full 32-bit 1 or 0 value. The result register is always the | 1052 // Materialize a full 32-bit 1 or 0 value. The result register is always the |
1032 // last output of the instruction. | 1053 // last output of the instruction. |
1033 Label false_value; | 1054 Label false_value; |
1034 DCHECK_NE(0u, instr->OutputCount()); | 1055 DCHECK_NE(0u, instr->OutputCount()); |
1035 Register result = i.OutputRegister(instr->OutputCount() - 1); | 1056 Register result = i.OutputRegister(instr->OutputCount() - 1); |
1036 Condition cc = kNoCondition; | 1057 Condition cc = kNoCondition; |
1037 | 1058 bool predicate; |
1038 // MIPS does not have condition code flags, so compare and branch are | 1059 // MIPS does not have condition code flags, so compare and branch are |
1039 // implemented differently than on the other arch's. The compare operations | 1060 // implemented differently than on the other arch's. The compare operations |
1040 // emit mips pseudo-instructions, which are checked and handled here. | 1061 // emit mips pseudo-instructions, which are checked and handled here. |
1041 | 1062 |
1042 // For materializations, we use delay slot to set the result true, and | |
1043 // in the false case, where we fall through the branch, we reset the result | |
1044 // false. | |
1045 | |
1046 if (instr->arch_opcode() == kMips64Tst) { | 1063 if (instr->arch_opcode() == kMips64Tst) { |
1047 cc = FlagsConditionToConditionTst(condition); | 1064 cc = FlagsConditionToConditionTst(predicate, condition); |
1048 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 1065 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1)); |
1049 __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); | 1066 __ xori(kScratchReg2, zero_reg, 1); // Create 1 for true. |
1050 __ li(result, Operand(1)); // In delay slot. | 1067 if (kArchVariant != kMips64r6) { |
| 1068 if (predicate) { |
| 1069 __ Movn(result, zero_reg, kScratchReg); |
| 1070 __ Movz(result, kScratchReg2, kScratchReg); |
| 1071 } else { |
| 1072 __ Movz(result, zero_reg, kScratchReg); |
| 1073 __ Movn(result, kScratchReg2, kScratchReg); |
| 1074 } |
| 1075 } else { |
| 1076 if (predicate) { |
| 1077 __ seleqz(result, kScratchReg2, kScratchReg); |
| 1078 } else { |
| 1079 __ selnez(result, kScratchReg2, kScratchReg); |
| 1080 } |
| 1081 } |
| 1082 return; |
1051 } else if (instr->arch_opcode() == kMips64Dadd || | 1083 } else if (instr->arch_opcode() == kMips64Dadd || |
1052 instr->arch_opcode() == kMips64Dsub) { | 1084 instr->arch_opcode() == kMips64Dsub) { |
1053 cc = FlagsConditionToConditionOvf(condition); | 1085 FlagsConditionToConditionOvf(predicate, condition); |
1054 __ dsra32(kScratchReg, i.OutputRegister(), 0); | 1086 // Check for overflow creates 1 or 0 for result. |
1055 __ sra(at, i.OutputRegister(), 31); | 1087 __ dsrl32(kScratchReg, i.OutputRegister(), 31); |
1056 __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(kScratchReg)); | 1088 __ srl(at, i.OutputRegister(), 31); |
1057 __ li(result, Operand(1)); // In delay slot. | 1089 __ xor_(result, kScratchReg, at); |
| 1090 if (!predicate) // Toggle result for not overflow. |
| 1091 __ xori(result, result, 1); |
| 1092 return; |
1058 } else if (instr->arch_opcode() == kMips64Cmp) { | 1093 } else if (instr->arch_opcode() == kMips64Cmp) { |
1059 Register left = i.InputRegister(0); | 1094 cc = FlagsConditionToConditionCmp(predicate, condition); |
1060 Operand right = i.InputOperand(1); | 1095 switch (cc) { |
1061 cc = FlagsConditionToConditionCmp(condition); | 1096 case eq: |
1062 __ Branch(USE_DELAY_SLOT, &done, cc, left, right); | 1097 case ne: { |
1063 __ li(result, Operand(1)); // In delay slot. | 1098 Register left = i.InputRegister(0); |
| 1099 Operand right = i.InputOperand(1); |
| 1100 __ Dsubu(kScratchReg, left, right); |
| 1101 __ xori(kScratchReg2, zero_reg, 1); |
| 1102 if (kArchVariant != kMips64r6) { |
| 1103 if (predicate) { |
| 1104 __ Movn(result, zero_reg, kScratchReg); |
| 1105 __ Movz(result, kScratchReg2, kScratchReg); |
| 1106 } else { |
| 1107 __ Movz(result, zero_reg, kScratchReg); |
| 1108 __ Movn(result, kScratchReg2, kScratchReg); |
| 1109 } |
| 1110 } else { |
| 1111 if (predicate) { |
| 1112 __ seleqz(result, kScratchReg2, kScratchReg); |
| 1113 } else { |
| 1114 __ selnez(result, kScratchReg2, kScratchReg); |
| 1115 } |
| 1116 } |
| 1117 } break; |
| 1118 case lt: |
| 1119 case ge: { |
| 1120 Register left = i.InputRegister(0); |
| 1121 Operand right = i.InputOperand(1); |
| 1122 __ Slt(result, left, right); |
| 1123 if (!predicate) { |
| 1124 __ xori(result, result, 1); |
| 1125 } |
| 1126 } break; |
| 1127 case gt: |
| 1128 case le: { |
| 1129 Register left = i.InputRegister(1); |
| 1130 Operand right = i.InputOperand(0); |
| 1131 __ Slt(result, left, right); |
| 1132 if (!predicate) { |
| 1133 __ xori(result, result, 1); |
| 1134 } |
| 1135 } break; |
| 1136 case lo: |
| 1137 case hs: { |
| 1138 Register left = i.InputRegister(0); |
| 1139 Operand right = i.InputOperand(1); |
| 1140 __ Sltu(result, left, right); |
| 1141 if (!predicate) { |
| 1142 __ xori(result, result, 1); |
| 1143 } |
| 1144 } break; |
| 1145 case hi: |
| 1146 case ls: { |
| 1147 Register left = i.InputRegister(1); |
| 1148 Operand right = i.InputOperand(0); |
| 1149 __ Sltu(result, left, right); |
| 1150 if (!predicate) { |
| 1151 __ xori(result, result, 1); |
| 1152 } |
| 1153 } break; |
| 1154 default: |
| 1155 UNREACHABLE(); |
| 1156 } |
| 1157 return; |
1064 } else if (instr->arch_opcode() == kMips64CmpD || | 1158 } else if (instr->arch_opcode() == kMips64CmpD || |
1065 instr->arch_opcode() == kMips64CmpS) { | 1159 instr->arch_opcode() == kMips64CmpS) { |
1066 FPURegister left = i.InputDoubleRegister(0); | 1160 FPURegister left = i.InputDoubleRegister(0); |
1067 FPURegister right = i.InputDoubleRegister(1); | 1161 FPURegister right = i.InputDoubleRegister(1); |
1068 | 1162 |
1069 bool predicate; | |
1070 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); | 1163 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); |
1071 if (kArchVariant != kMips64r6) { | 1164 if (kArchVariant != kMips64r6) { |
1072 __ li(result, Operand(1)); | 1165 __ li(result, Operand(1)); |
1073 if (instr->arch_opcode() == kMips64CmpD) { | 1166 if (instr->arch_opcode() == kMips64CmpD) { |
1074 __ c(cc, D, left, right); | 1167 __ c(cc, D, left, right); |
1075 } else { | 1168 } else { |
1076 DCHECK(instr->arch_opcode() == kMips64CmpS); | 1169 DCHECK(instr->arch_opcode() == kMips64CmpS); |
1077 __ c(cc, S, left, right); | 1170 __ c(cc, S, left, right); |
1078 } | 1171 } |
1079 if (predicate) { | 1172 if (predicate) { |
(...skipping 13 matching lines...) Expand all Loading... |
1093 if (!predicate) // Toggle result for not equal. | 1186 if (!predicate) // Toggle result for not equal. |
1094 __ xori(result, result, 1); | 1187 __ xori(result, result, 1); |
1095 } | 1188 } |
1096 return; | 1189 return; |
1097 } else { | 1190 } else { |
1098 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", | 1191 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", |
1099 instr->arch_opcode()); | 1192 instr->arch_opcode()); |
1100 TRACE_UNIMPL(); | 1193 TRACE_UNIMPL(); |
1101 UNIMPLEMENTED(); | 1194 UNIMPLEMENTED(); |
1102 } | 1195 } |
1103 // Fallthru case is the false materialization. | |
1104 __ bind(&false_value); | |
1105 __ li(result, Operand(static_cast<int64_t>(0))); | |
1106 __ bind(&done); | |
1107 } | 1196 } |
1108 | 1197 |
1109 | 1198 |
1110 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { | 1199 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { |
1111 MipsOperandConverter i(this, instr); | 1200 MipsOperandConverter i(this, instr); |
1112 Register input = i.InputRegister(0); | 1201 Register input = i.InputRegister(0); |
1113 for (size_t index = 2; index < instr->InputCount(); index += 2) { | 1202 for (size_t index = 2; index < instr->InputCount(); index += 2) { |
1114 __ li(at, Operand(i.InputInt32(index + 0))); | 1203 __ li(at, Operand(i.InputInt32(index + 0))); |
1115 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); | 1204 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); |
1116 } | 1205 } |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 padding_size -= v8::internal::Assembler::kInstrSize; | 1542 padding_size -= v8::internal::Assembler::kInstrSize; |
1454 } | 1543 } |
1455 } | 1544 } |
1456 } | 1545 } |
1457 | 1546 |
1458 #undef __ | 1547 #undef __ |
1459 | 1548 |
1460 } // namespace compiler | 1549 } // namespace compiler |
1461 } // namespace internal | 1550 } // namespace internal |
1462 } // namespace v8 | 1551 } // namespace v8 |
OLD | NEW |