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/mips/macro-assembler-mips.h" | 9 #include "src/mips/macro-assembler-mips.h" |
10 #include "src/scopes.h" | 10 #include "src/scopes.h" |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 }; | 193 }; |
194 | 194 |
195 | 195 |
196 class OutOfLineCeil final : public OutOfLineRound { | 196 class OutOfLineCeil final : public OutOfLineRound { |
197 public: | 197 public: |
198 OutOfLineCeil(CodeGenerator* gen, DoubleRegister result) | 198 OutOfLineCeil(CodeGenerator* gen, DoubleRegister result) |
199 : OutOfLineRound(gen, result) {} | 199 : OutOfLineRound(gen, result) {} |
200 }; | 200 }; |
201 | 201 |
202 | 202 |
203 Condition FlagsConditionToConditionCmp(FlagsCondition condition) { | 203 Condition FlagsConditionToConditionCmp(bool& predicate, |
paul.l...
2015/09/03 22:27:39
It took me some staring at the code to figure out
paul.l...
2015/09/04 03:33:58
OK, I think we both overcomplicated this. When I s
| |
204 FlagsCondition condition) { | |
204 switch (condition) { | 205 switch (condition) { |
205 case kEqual: | 206 case kEqual: |
207 predicate = true; | |
206 return eq; | 208 return eq; |
207 case kNotEqual: | 209 case kNotEqual: |
210 predicate = false; | |
208 return ne; | 211 return ne; |
209 case kSignedLessThan: | 212 case kSignedLessThan: |
213 predicate = true; | |
210 return lt; | 214 return lt; |
211 case kSignedGreaterThanOrEqual: | 215 case kSignedGreaterThanOrEqual: |
216 predicate = false; | |
212 return ge; | 217 return ge; |
213 case kSignedLessThanOrEqual: | 218 case kSignedLessThanOrEqual: |
219 predicate = false; | |
214 return le; | 220 return le; |
215 case kSignedGreaterThan: | 221 case kSignedGreaterThan: |
222 predicate = true; | |
216 return gt; | 223 return gt; |
217 case kUnsignedLessThan: | 224 case kUnsignedLessThan: |
225 predicate = true; | |
218 return lo; | 226 return lo; |
219 case kUnsignedGreaterThanOrEqual: | 227 case kUnsignedGreaterThanOrEqual: |
228 predicate = false; | |
220 return hs; | 229 return hs; |
221 case kUnsignedLessThanOrEqual: | 230 case kUnsignedLessThanOrEqual: |
231 predicate = false; | |
222 return ls; | 232 return ls; |
223 case kUnsignedGreaterThan: | 233 case kUnsignedGreaterThan: |
234 predicate = true; | |
224 return hi; | 235 return hi; |
225 case kUnorderedEqual: | 236 case kUnorderedEqual: |
226 case kUnorderedNotEqual: | 237 case kUnorderedNotEqual: |
238 predicate = true; | |
227 break; | 239 break; |
228 default: | 240 default: |
241 predicate = true; | |
229 break; | 242 break; |
230 } | 243 } |
231 UNREACHABLE(); | 244 UNREACHABLE(); |
232 return kNoCondition; | 245 return kNoCondition; |
233 } | 246 } |
234 | 247 |
235 | 248 |
236 Condition FlagsConditionToConditionTst(FlagsCondition condition) { | 249 Condition FlagsConditionToConditionTst(bool& predicate, |
250 FlagsCondition condition) { | |
237 switch (condition) { | 251 switch (condition) { |
238 case kNotEqual: | 252 case kNotEqual: |
253 predicate = false; | |
239 return ne; | 254 return ne; |
240 case kEqual: | 255 case kEqual: |
256 predicate = true; | |
241 return eq; | 257 return eq; |
242 default: | 258 default: |
259 predicate = true; | |
243 break; | 260 break; |
244 } | 261 } |
245 UNREACHABLE(); | 262 UNREACHABLE(); |
246 return kNoCondition; | 263 return kNoCondition; |
247 } | 264 } |
248 | 265 |
249 | 266 |
250 Condition FlagsConditionToConditionOvf(FlagsCondition condition) { | 267 Condition FlagsConditionToConditionOvf(bool& predicate, |
268 FlagsCondition condition) { | |
251 switch (condition) { | 269 switch (condition) { |
252 case kOverflow: | 270 case kOverflow: |
271 predicate = true; | |
253 return lt; | 272 return lt; |
254 case kNotOverflow: | 273 case kNotOverflow: |
274 predicate = false; | |
255 return ge; | 275 return ge; |
256 default: | 276 default: |
277 predicate = true; | |
257 break; | 278 break; |
258 } | 279 } |
259 UNREACHABLE(); | 280 UNREACHABLE(); |
260 return kNoCondition; | 281 return kNoCondition; |
261 } | 282 } |
262 | 283 |
263 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, | 284 FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate, |
264 FlagsCondition condition) { | 285 FlagsCondition condition) { |
265 switch (condition) { | 286 switch (condition) { |
266 case kEqual: | 287 case kEqual: |
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
883 return false; | 904 return false; |
884 } | 905 } |
885 | 906 |
886 | 907 |
887 // Assembles branches after an instruction. | 908 // Assembles branches after an instruction. |
888 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { | 909 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { |
889 MipsOperandConverter i(this, instr); | 910 MipsOperandConverter i(this, instr); |
890 Label* tlabel = branch->true_label; | 911 Label* tlabel = branch->true_label; |
891 Label* flabel = branch->false_label; | 912 Label* flabel = branch->false_label; |
892 Condition cc = kNoCondition; | 913 Condition cc = kNoCondition; |
893 | 914 bool predicate; |
894 // MIPS does not have condition code flags, so compare and branch are | 915 // MIPS does not have condition code flags, so compare and branch are |
895 // implemented differently than on the other arch's. The compare operations | 916 // implemented differently than on the other arch's. The compare operations |
896 // emit mips pseudo-instructions, which are handled here by branch | 917 // emit mips pseudo-instructions, which are handled here by branch |
897 // instructions that do the actual comparison. Essential that the input | 918 // instructions that do the actual comparison. Essential that the input |
898 // registers to compare pseudo-op are not modified before this branch op, as | 919 // registers to compare pseudo-op are not modified before this branch op, as |
899 // they are tested here. | 920 // they are tested here. |
900 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were | 921 // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were |
901 // not separated by other instructions. | 922 // not separated by other instructions. |
902 | 923 |
903 if (instr->arch_opcode() == kMipsTst) { | 924 if (instr->arch_opcode() == kMipsTst) { |
904 cc = FlagsConditionToConditionTst(branch->condition); | 925 cc = FlagsConditionToConditionTst(predicate, branch->condition); |
905 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 926 __ And(at, i.InputRegister(0), i.InputOperand(1)); |
906 __ Branch(tlabel, cc, at, Operand(zero_reg)); | 927 __ Branch(tlabel, cc, at, Operand(zero_reg)); |
907 } else if (instr->arch_opcode() == kMipsAddOvf || | 928 } else if (instr->arch_opcode() == kMipsAddOvf || |
908 instr->arch_opcode() == kMipsSubOvf) { | 929 instr->arch_opcode() == kMipsSubOvf) { |
909 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. | 930 // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow. |
910 cc = FlagsConditionToConditionOvf(branch->condition); | 931 cc = FlagsConditionToConditionOvf(predicate, branch->condition); |
911 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); | 932 __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg)); |
912 } else if (instr->arch_opcode() == kMipsCmp) { | 933 } else if (instr->arch_opcode() == kMipsCmp) { |
913 cc = FlagsConditionToConditionCmp(branch->condition); | 934 cc = FlagsConditionToConditionCmp(predicate, branch->condition); |
914 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); | 935 __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1)); |
915 } else if (instr->arch_opcode() == kMipsCmpS) { | 936 } else if (instr->arch_opcode() == kMipsCmpS) { |
916 if (!convertCondition(branch->condition, cc)) { | 937 if (!convertCondition(branch->condition, cc)) { |
917 UNSUPPORTED_COND(kMips64CmpS, branch->condition); | 938 UNSUPPORTED_COND(kMips64CmpS, branch->condition); |
918 } | 939 } |
919 __ BranchF32(tlabel, NULL, cc, i.InputSingleRegister(0), | 940 __ BranchF32(tlabel, NULL, cc, i.InputSingleRegister(0), |
920 i.InputSingleRegister(1)); | 941 i.InputSingleRegister(1)); |
921 } else if (instr->arch_opcode() == kMipsCmpD) { | 942 } else if (instr->arch_opcode() == kMipsCmpD) { |
922 if (!convertCondition(branch->condition, cc)) { | 943 if (!convertCondition(branch->condition, cc)) { |
923 UNSUPPORTED_COND(kMips64CmpD, branch->condition); | 944 UNSUPPORTED_COND(kMips64CmpD, branch->condition); |
(...skipping 19 matching lines...) Expand all Loading... | |
943 FlagsCondition condition) { | 964 FlagsCondition condition) { |
944 MipsOperandConverter i(this, instr); | 965 MipsOperandConverter i(this, instr); |
945 Label done; | 966 Label done; |
946 | 967 |
947 // Materialize a full 32-bit 1 or 0 value. The result register is always the | 968 // Materialize a full 32-bit 1 or 0 value. The result register is always the |
948 // last output of the instruction. | 969 // last output of the instruction. |
949 Label false_value; | 970 Label false_value; |
950 DCHECK_NE(0u, instr->OutputCount()); | 971 DCHECK_NE(0u, instr->OutputCount()); |
951 Register result = i.OutputRegister(instr->OutputCount() - 1); | 972 Register result = i.OutputRegister(instr->OutputCount() - 1); |
952 Condition cc = kNoCondition; | 973 Condition cc = kNoCondition; |
953 | 974 bool predicate; |
954 // MIPS does not have condition code flags, so compare and branch are | 975 // MIPS does not have condition code flags, so compare and branch are |
955 // implemented differently than on the other arch's. The compare operations | 976 // implemented differently than on the other arch's. The compare operations |
956 // emit mips psuedo-instructions, which are checked and handled here. | 977 // emit mips psuedo-instructions, which are checked and handled here. |
957 | 978 |
958 // For materializations, we use delay slot to set the result true, and | |
959 // in the false case, where we fall thru the branch, we reset the result | |
960 // false. | |
961 | |
962 if (instr->arch_opcode() == kMipsTst) { | 979 if (instr->arch_opcode() == kMipsTst) { |
963 cc = FlagsConditionToConditionTst(condition); | 980 cc = FlagsConditionToConditionTst(predicate, condition); |
964 __ And(at, i.InputRegister(0), i.InputOperand(1)); | 981 __ And(kScratchReg, i.InputRegister(0), i.InputOperand(1)); |
965 __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg)); | 982 __ xori(kScratchReg2, zero_reg, 1); // Create 1 for true. |
paul.l...
2015/09/03 22:27:39
Prefer li(kScratchReg2, 1) here, for readability.
| |
966 __ li(result, Operand(1)); // In delay slot. | 983 if (!IsMipsArchVariant(kMips32r6)) { |
paul.l...
2015/09/03 22:27:39
I find that 'negative-conditions' -- if (not-somet
| |
967 | 984 if (predicate) { |
985 __ Movn(result, zero_reg, kScratchReg); | |
986 __ Movz(result, kScratchReg2, kScratchReg); | |
paul.l...
2015/09/03 22:27:39
If you refactor the code a bit, you can get by wit
paul.l...
2015/09/04 03:33:58
Never mind the last paragraph of prev comment (quo
| |
987 } else { | |
988 __ Movz(result, zero_reg, kScratchReg); | |
989 __ Movn(result, kScratchReg2, kScratchReg); | |
990 } | |
991 } else { | |
992 if (predicate) { | |
993 __ seleqz(result, kScratchReg2, kScratchReg); | |
994 } else { | |
995 __ selnez(result, kScratchReg2, kScratchReg); | |
996 } | |
997 } | |
998 return; | |
968 } else if (instr->arch_opcode() == kMipsAddOvf || | 999 } else if (instr->arch_opcode() == kMipsAddOvf || |
969 instr->arch_opcode() == kMipsSubOvf) { | 1000 instr->arch_opcode() == kMipsSubOvf) { |
970 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. | 1001 // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow. |
971 cc = FlagsConditionToConditionOvf(condition); | 1002 cc = FlagsConditionToConditionOvf(predicate, condition); |
972 __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg)); | 1003 // Return 1 on overflow. |
973 __ li(result, Operand(1)); // In delay slot. | 1004 __ Slt(result, kCompareReg, Operand(zero_reg)); |
974 | 1005 if (!predicate) // Invert result on not overflow. |
1006 __ xori(result, result, 1); | |
1007 return; | |
975 } else if (instr->arch_opcode() == kMipsCmp) { | 1008 } else if (instr->arch_opcode() == kMipsCmp) { |
976 Register left = i.InputRegister(0); | 1009 cc = FlagsConditionToConditionCmp(predicate, condition); |
977 Operand right = i.InputOperand(1); | 1010 switch (cc) { |
978 cc = FlagsConditionToConditionCmp(condition); | 1011 case eq: |
979 __ Branch(USE_DELAY_SLOT, &done, cc, left, right); | 1012 case ne: { |
980 __ li(result, Operand(1)); // In delay slot. | 1013 Register left = i.InputRegister(0); |
981 | 1014 Operand right = i.InputOperand(1); |
1015 __ Subu(kScratchReg, left, right); | |
1016 __ xori(kScratchReg2, zero_reg, 1); | |
1017 if (!IsMipsArchVariant(kMips32r6)) { | |
1018 if (predicate) { | |
1019 __ Movn(result, zero_reg, kScratchReg); | |
1020 __ Movz(result, kScratchReg2, kScratchReg); | |
1021 } else { | |
1022 __ Movz(result, zero_reg, kScratchReg); | |
1023 __ Movn(result, kScratchReg2, kScratchReg); | |
1024 } | |
1025 } else { | |
1026 if (predicate) { | |
1027 __ seleqz(result, kScratchReg2, kScratchReg); | |
1028 } else { | |
1029 __ selnez(result, kScratchReg2, kScratchReg); | |
1030 } | |
1031 } | |
1032 } break; | |
1033 case lt: | |
1034 case ge: { | |
1035 Register left = i.InputRegister(0); | |
1036 Operand right = i.InputOperand(1); | |
1037 __ Slt(result, left, right); | |
1038 if (!predicate) { | |
1039 __ xori(result, result, 1); | |
1040 } | |
1041 } break; | |
1042 case gt: | |
1043 case le: { | |
1044 Register left = i.InputRegister(1); | |
1045 Operand right = i.InputOperand(0); | |
1046 __ Slt(result, left, right); | |
1047 if (!predicate) { | |
1048 __ xori(result, result, 1); | |
1049 } | |
1050 } break; | |
1051 case lo: | |
1052 case hs: { | |
1053 Register left = i.InputRegister(0); | |
1054 Operand right = i.InputOperand(1); | |
1055 __ Sltu(result, left, right); | |
1056 if (!predicate) { | |
1057 __ xori(result, result, 1); | |
1058 } | |
1059 } break; | |
1060 case hi: | |
1061 case ls: { | |
1062 Register left = i.InputRegister(1); | |
1063 Operand right = i.InputOperand(0); | |
1064 __ Sltu(result, left, right); | |
1065 if (!predicate) { | |
1066 __ xori(result, result, 1); | |
1067 } | |
1068 } break; | |
1069 default: | |
1070 UNREACHABLE(); | |
1071 } | |
1072 return; | |
982 } else if (instr->arch_opcode() == kMipsCmpD || | 1073 } else if (instr->arch_opcode() == kMipsCmpD || |
983 instr->arch_opcode() == kMipsCmpS) { | 1074 instr->arch_opcode() == kMipsCmpS) { |
984 FPURegister left = i.InputDoubleRegister(0); | 1075 FPURegister left = i.InputDoubleRegister(0); |
985 FPURegister right = i.InputDoubleRegister(1); | 1076 FPURegister right = i.InputDoubleRegister(1); |
986 | 1077 |
987 bool predicate; | |
988 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); | 1078 FPUCondition cc = FlagsConditionToConditionCmpFPU(predicate, condition); |
989 if (!IsMipsArchVariant(kMips32r6)) { | 1079 if (!IsMipsArchVariant(kMips32r6)) { |
990 __ li(result, Operand(1)); | 1080 __ li(result, Operand(1)); |
991 if (instr->arch_opcode() == kMipsCmpD) { | 1081 if (instr->arch_opcode() == kMipsCmpD) { |
992 __ c(cc, D, left, right); | 1082 __ c(cc, D, left, right); |
993 } else { | 1083 } else { |
994 DCHECK(instr->arch_opcode() == kMipsCmpS); | 1084 DCHECK(instr->arch_opcode() == kMipsCmpS); |
995 __ c(cc, S, left, right); | 1085 __ c(cc, S, left, right); |
996 } | 1086 } |
997 if (predicate) { | 1087 if (predicate) { |
(...skipping 13 matching lines...) Expand all Loading... | |
1011 if (!predicate) // Toggle result for not equal. | 1101 if (!predicate) // Toggle result for not equal. |
1012 __ xori(result, result, 1); | 1102 __ xori(result, result, 1); |
1013 } | 1103 } |
1014 return; | 1104 return; |
1015 } else { | 1105 } else { |
1016 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", | 1106 PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n", |
1017 instr->arch_opcode()); | 1107 instr->arch_opcode()); |
1018 TRACE_UNIMPL(); | 1108 TRACE_UNIMPL(); |
1019 UNIMPLEMENTED(); | 1109 UNIMPLEMENTED(); |
1020 } | 1110 } |
1021 | |
1022 // Fallthrough case is the false materialization. | |
1023 __ bind(&false_value); | |
1024 __ li(result, Operand(0)); | |
1025 __ bind(&done); | |
1026 } | 1111 } |
1027 | 1112 |
1028 | 1113 |
1029 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { | 1114 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { |
1030 MipsOperandConverter i(this, instr); | 1115 MipsOperandConverter i(this, instr); |
1031 Register input = i.InputRegister(0); | 1116 Register input = i.InputRegister(0); |
1032 for (size_t index = 2; index < instr->InputCount(); index += 2) { | 1117 for (size_t index = 2; index < instr->InputCount(); index += 2) { |
1033 __ li(at, Operand(i.InputInt32(index + 0))); | 1118 __ li(at, Operand(i.InputInt32(index + 0))); |
1034 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); | 1119 __ beq(input, at, GetLabel(i.InputRpo(index + 1))); |
1035 } | 1120 } |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1367 } | 1452 } |
1368 } | 1453 } |
1369 } | 1454 } |
1370 } | 1455 } |
1371 | 1456 |
1372 #undef __ | 1457 #undef __ |
1373 | 1458 |
1374 } // namespace compiler | 1459 } // namespace compiler |
1375 } // namespace internal | 1460 } // namespace internal |
1376 } // namespace v8 | 1461 } // namespace v8 |
OLD | NEW |