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 lt; | 273 return lt; |
255 case kNotOverflow: | 274 case kNotOverflow: |
| 275 predicate = false; |
256 return ge; | 276 return ge; |
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 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, | 285 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, |
265 FlagsCondition condition) { | 286 FlagsCondition condition) { |
266 switch (condition) { | 287 switch (condition) { |
267 case kEqual: | 288 case kEqual: |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 return false; | 918 return false; |
898 } | 919 } |
899 | 920 |
900 | 921 |
901 // Assembles branches after an instruction. | 922 // Assembles branches after an instruction. |
902 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { | 923 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { |
903 MipsOperandConverter i(this, instr); | 924 MipsOperandConverter i(this, instr); |
904 Label* tlabel = branch->true_label; | 925 Label* tlabel = branch->true_label; |
905 Label* flabel = branch->false_label; | 926 Label* flabel = branch->false_label; |
906 Condition cc = kNoCondition; | 927 Condition cc = kNoCondition; |
907 | 928 bool predicate; |
908 // MIPS does not have condition code flags, so compare and branch are | 929 // MIPS does not have condition code flags, so compare and branch are |
909 // implemented differently than on the other arch's. The compare operations | 930 // implemented differently than on the other arch's. The compare operations |
910 // emit mips pseudo-instructions, which are handled here by branch | 931 // emit mips pseudo-instructions, which are handled here by branch |
911 // instructions that do the actual comparison. Essential that the input | 932 // instructions that do the actual comparison. Essential that the input |
912 // registers to compare pseudo-op are not modified before this branch op, as | 933 // registers to compare pseudo-op are not modified before this branch op, as |
913 // they are tested here. | 934 // they are tested here. |
914 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were | 935 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were |
915 // not separated by other instructions. | 936 // not separated by other instructions. |
916 | 937 |
917 if (instr->arch_opcode() == kMipsTst) { | 938 if (instr->arch_opcode() == kMipsTst) { |
918 cc = FlagsConditionToConditionTst(branch->condition); | 939 cc = FlagsConditionToConditionTst(predicate, branch->condition); |
919 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 940 __ And(at, i.InputRegister(0), i.InputOperand(1)); |
920 __ Branch(tlabel, cc, at, Operand(zero_reg)); | 941 __ Branch(tlabel, cc, at, Operand(zero_reg)); |
921 } else if (instr->arch_opcode() == kMipsAddOvf || | 942 } else if (instr->arch_opcode() == kMipsAddOvf || |
922 instr->arch_opcode() == kMipsSubOvf) { | 943 instr->arch_opcode() == kMipsSubOvf) { |
923 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. | 944 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. |
924 cc = FlagsConditionToConditionOvf(branch->condition); | 945 cc = FlagsConditionToConditionOvf(predicate, branch->condition); |
925 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); | 946 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); |
926 } else if (instr->arch_opcode() == kMipsCmp) { | 947 } else if (instr->arch_opcode() == kMipsCmp) { |
927 cc = FlagsConditionToConditionCmp(branch->condition); | 948 cc = FlagsConditionToConditionCmp(predicate, branch->condition); |
928 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); | 949 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); |
929 } else if (instr->arch_opcode() == kMipsCmpS) { | 950 } else if (instr->arch_opcode() == kMipsCmpS) { |
930 if (!convertCondition(branch->condition, cc)) { | 951 if (!convertCondition(branch->condition, cc)) { |
931 UNSUPPORTED_COND(kMips64CmpS, branch->condition); | 952 UNSUPPORTED_COND(kMips64CmpS, branch->condition); |
932 } | 953 } |
933 __ BranchF32(tlabel, NULL, cc, i.InputSingleRegister(0), | 954 __ BranchF32(tlabel, NULL, cc, i.InputSingleRegister(0), |
934 i.InputSingleRegister(1)); | 955 i.InputSingleRegister(1)); |
935 } else if (instr->arch_opcode() == kMipsCmpD) { | 956 } else if (instr->arch_opcode() == kMipsCmpD) { |
936 if (!convertCondition(branch->condition, cc)) { | 957 if (!convertCondition(branch->condition, cc)) { |
937 UNSUPPORTED_COND(kMips64CmpD, branch->condition); | 958 UNSUPPORTED_COND(kMips64CmpD, branch->condition); |
(...skipping 19 matching lines...) Expand all Loading... |
957 FlagsCondition condition) { | 978 FlagsCondition condition) { |
958 MipsOperandConverter i(this, instr); | 979 MipsOperandConverter i(this, instr); |
959 Label done; | 980 Label done; |
960 | 981 |
961 // Materialize a full 32-bit 1 or 0 value. The result register is always the | 982 // Materialize a full 32-bit 1 or 0 value. The result register is always the |
962 // last output of the instruction. | 983 // last output of the instruction. |
963 Label false_value; | 984 Label false_value; |
964 DCHECK_NE(0u, instr->OutputCount()); | 985 DCHECK_NE(0u, instr->OutputCount()); |
965 Register result = i.OutputRegister(instr->OutputCount() - 1); | 986 Register result = i.OutputRegister(instr->OutputCount() - 1); |
966 Condition cc = kNoCondition; | 987 Condition cc = kNoCondition; |
967 | 988 bool predicate; |
968 // MIPS does not have condition code flags, so compare and branch are | 989 // MIPS does not have condition code flags, so compare and branch are |
969 // implemented differently than on the other arch's. The compare operations | 990 // implemented differently than on the other arch's. The compare operations |
970 // emit mips psuedo-instructions, which are checked and handled here. | 991 // emit mips psuedo-instructions, which are checked and handled here. |
971 | 992 |
972 // For materializations, we use delay slot to set the result true, and | |
973 // in the false case, where we fall thru the branch, we reset the result | |
974 // false. | |
975 | |
976 if (instr->arch_opcode() == kMipsTst) { | 993 if (instr->arch_opcode() == kMipsTst) { |
977 cc = FlagsConditionToConditionTst(condition); | 994 cc = FlagsConditionToConditionTst(predicate, condition); |
978 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 995 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1)); |
979 __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); | 996 if (IsMipsArchVariant(kMips32r6)) { |
980 __ li(result, Operand(1)); // In delay slot. | 997 __ li(kScratchReg2, 1); // Create 1 for true. |
981 | 998 if (cc == eq) { |
| 999 __ seleqz(result, kScratchReg2, kScratchReg); |
| 1000 } else { |
| 1001 __ selnez(result, kScratchReg2, kScratchReg); |
| 1002 } |
| 1003 } else { |
| 1004 __ li(result, 1); |
| 1005 if (cc == eq) { |
| 1006 __ Movn(result, zero_reg, kScratchReg); |
| 1007 } else { |
| 1008 __ Movz(result, zero_reg, kScratchReg); |
| 1009 } |
| 1010 } |
| 1011 return; |
982 } else if (instr->arch_opcode() == kMipsAddOvf || | 1012 } else if (instr->arch_opcode() == kMipsAddOvf || |
983 instr->arch_opcode() == kMipsSubOvf) { | 1013 instr->arch_opcode() == kMipsSubOvf) { |
984 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. | 1014 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. |
985 cc = FlagsConditionToConditionOvf(condition); | 1015 cc = FlagsConditionToConditionOvf(predicate, condition); |
986 __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg)); | 1016 // Return 1 on overflow. |
987 __ li(result, Operand(1)); // In delay slot. | 1017 __ Slt(result, kCompareReg, Operand(zero_reg)); |
988 | 1018 if (cc == ne) // Invert result on not overflow. |
| 1019 __ xori(result, result, 1); |
| 1020 return; |
989 } else if (instr->arch_opcode() == kMipsCmp) { | 1021 } else if (instr->arch_opcode() == kMipsCmp) { |
990 Register left = i.InputRegister(0); | 1022 cc = FlagsConditionToConditionCmp(predicate, condition); |
991 Operand right = i.InputOperand(1); | 1023 switch (cc) { |
992 cc = FlagsConditionToConditionCmp(condition); | 1024 case eq: |
993 __ Branch(USE_DELAY_SLOT, &done, cc, left, right); | 1025 case ne: { |
994 __ li(result, Operand(1)); // In delay slot. | 1026 Register left = i.InputRegister(0); |
995 | 1027 Operand right = i.InputOperand(1); |
| 1028 __ Subu(kScratchReg, left, right); |
| 1029 if (IsMipsArchVariant(kMips32r6)) { |
| 1030 __ li(kScratchReg2, 1); |
| 1031 if (cc == eq) { |
| 1032 __ seleqz(result, kScratchReg2, kScratchReg); |
| 1033 } else { |
| 1034 __ selnez(result, kScratchReg2, kScratchReg); |
| 1035 } |
| 1036 } else { |
| 1037 __ li(result, 1); |
| 1038 if (cc == eq) { |
| 1039 __ Movn(result, zero_reg, kScratchReg); |
| 1040 } else { |
| 1041 __ Movz(result, zero_reg, kScratchReg); |
| 1042 } |
| 1043 } |
| 1044 } break; |
| 1045 case lt: |
| 1046 case ge: { |
| 1047 Register left = i.InputRegister(0); |
| 1048 Operand right = i.InputOperand(1); |
| 1049 __ Slt(result, left, right); |
| 1050 if (cc == ge) { |
| 1051 __ xori(result, result, 1); |
| 1052 } |
| 1053 } break; |
| 1054 case gt: |
| 1055 case le: { |
| 1056 Register left = i.InputRegister(1); |
| 1057 Operand right = i.InputOperand(0); |
| 1058 __ Slt(result, left, right); |
| 1059 if (cc == le) { |
| 1060 __ xori(result, result, 1); |
| 1061 } |
| 1062 } break; |
| 1063 case lo: |
| 1064 case hs: { |
| 1065 Register left = i.InputRegister(0); |
| 1066 Operand right = i.InputOperand(1); |
| 1067 __ Sltu(result, left, right); |
| 1068 if (cc == hs) { |
| 1069 __ xori(result, result, 1); |
| 1070 } |
| 1071 } break; |
| 1072 case hi: |
| 1073 case ls: { |
| 1074 Register left = i.InputRegister(1); |
| 1075 Operand right = i.InputOperand(0); |
| 1076 __ Sltu(result, left, right); |
| 1077 if (cc == ls) { |
| 1078 __ xori(result, result, 1); |
| 1079 } |
| 1080 } break; |
| 1081 default: |
| 1082 UNREACHABLE(); |
| 1083 } |
| 1084 return; |
996 } else if (instr->arch_opcode() == kMipsCmpD || | 1085 } else if (instr->arch_opcode() == kMipsCmpD || |
997 instr->arch_opcode() == kMipsCmpS) { | 1086 instr->arch_opcode() == kMipsCmpS) { |
998 FPURegister left = i.InputDoubleRegister(0); | 1087 FPURegister left = i.InputDoubleRegister(0); |
999 FPURegister right = i.InputDoubleRegister(1); | 1088 FPURegister right = i.InputDoubleRegister(1); |
1000 | 1089 |
1001 bool predicate; | |
1002 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); | 1090 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); |
1003 if (!IsMipsArchVariant(kMips32r6)) { | 1091 if (!IsMipsArchVariant(kMips32r6)) { |
1004 __ li(result, Operand(1)); | 1092 __ li(result, Operand(1)); |
1005 if (instr->arch_opcode() == kMipsCmpD) { | 1093 if (instr->arch_opcode() == kMipsCmpD) { |
1006 __ c(cc, D, left, right); | 1094 __ c(cc, D, left, right); |
1007 } else { | 1095 } else { |
1008 DCHECK(instr->arch_opcode() == kMipsCmpS); | 1096 DCHECK(instr->arch_opcode() == kMipsCmpS); |
1009 __ c(cc, S, left, right); | 1097 __ c(cc, S, left, right); |
1010 } | 1098 } |
1011 if (predicate) { | 1099 if (predicate) { |
(...skipping 13 matching lines...) Expand all Loading... |
1025 if (!predicate) // Toggle result for not equal. | 1113 if (!predicate) // Toggle result for not equal. |
1026 __ xori(result, result, 1); | 1114 __ xori(result, result, 1); |
1027 } | 1115 } |
1028 return; | 1116 return; |
1029 } else { | 1117 } else { |
1030 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", | 1118 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", |
1031 instr->arch_opcode()); | 1119 instr->arch_opcode()); |
1032 TRACE_UNIMPL(); | 1120 TRACE_UNIMPL(); |
1033 UNIMPLEMENTED(); | 1121 UNIMPLEMENTED(); |
1034 } | 1122 } |
1035 | |
1036 // Fallthrough case is the false materialization. | |
1037 __ bind(&false_value); | |
1038 __ li(result, Operand(0)); | |
1039 __ bind(&done); | |
1040 } | 1123 } |
1041 | 1124 |
1042 | 1125 |
1043 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { | 1126 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { |
1044 MipsOperandConverter i(this, instr); | 1127 MipsOperandConverter i(this, instr); |
1045 Register input = i.InputRegister(0); | 1128 Register input = i.InputRegister(0); |
1046 for (size_t index = 2; index < instr->InputCount(); index += 2) { | 1129 for (size_t index = 2; index < instr->InputCount(); index += 2) { |
1047 __ li(at, Operand(i.InputInt32(index + 0))); | 1130 __ li(at, Operand(i.InputInt32(index + 0))); |
1048 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); | 1131 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); |
1049 } | 1132 } |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1384 padding_size -= v8::internal::Assembler::kInstrSize; | 1467 padding_size -= v8::internal::Assembler::kInstrSize; |
1385 } | 1468 } |
1386 } | 1469 } |
1387 } | 1470 } |
1388 | 1471 |
1389 #undef __ | 1472 #undef __ |
1390 | 1473 |
1391 } // namespace compiler | 1474 } // namespace compiler |
1392 } // namespace internal | 1475 } // namespace internal |
1393 } // namespace v8 | 1476 } // namespace v8 |
OLD | NEW |