| 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 case Constant::kRpoNumber: | 73 case Constant::kRpoNumber: |
| 74 UNREACHABLE(); // TODO(titzer): RPO immediates on mips? | 74 UNREACHABLE(); // TODO(titzer): RPO immediates on mips? |
| 75 break; | 75 break; |
| 76 } | 76 } |
| 77 UNREACHABLE(); | 77 UNREACHABLE(); |
| 78 return Operand(zero_reg); | 78 return Operand(zero_reg); |
| 79 } | 79 } |
| 80 | 80 |
| 81 Operand InputOperand(size_t index) { | 81 Operand InputOperand(size_t index) { |
| 82 InstructionOperand* op = instr_->InputAt(index); | 82 InstructionOperand* op = instr_->InputAt(index); |
| 83 if (op->IsRegister()) { | 83 if (op->GeneratesRegister()) { |
| 84 return Operand(ToRegister(op)); | 84 return Operand(ToRegister(op)); |
| 85 } | 85 } |
| 86 return InputImmediate(index); | 86 return InputImmediate(index); |
| 87 } | 87 } |
| 88 | 88 |
| 89 MemOperand MemoryOperand(size_t* first_index) { | 89 MemOperand MemoryOperand(size_t* first_index) { |
| 90 const size_t index = *first_index; | 90 const size_t index = *first_index; |
| 91 switch (AddressingModeField::decode(instr_->opcode())) { | 91 switch (AddressingModeField::decode(instr_->opcode())) { |
| 92 case kMode_None: | 92 case kMode_None: |
| 93 break; | 93 break; |
| 94 case kMode_MRI: | 94 case kMode_MRI: |
| 95 *first_index += 2; | 95 *first_index += 2; |
| 96 return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); | 96 return MemOperand(InputRegister(index + 0), InputInt32(index + 1)); |
| 97 case kMode_MRR: | 97 case kMode_MRR: |
| 98 // TODO(plind): r6 address mode, to be implemented ... | 98 // TODO(plind): r6 address mode, to be implemented ... |
| 99 UNREACHABLE(); | 99 UNREACHABLE(); |
| 100 } | 100 } |
| 101 UNREACHABLE(); | 101 UNREACHABLE(); |
| 102 return MemOperand(no_reg); | 102 return MemOperand(no_reg); |
| 103 } | 103 } |
| 104 | 104 |
| 105 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); } | 105 MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); } |
| 106 | 106 |
| 107 MemOperand ToMemOperand(InstructionOperand* op) const { | 107 MemOperand ToMemOperand(InstructionOperand* op) const { |
| 108 DCHECK(op != NULL); | 108 DCHECK(op != NULL); |
| 109 DCHECK(!op->IsRegister()); | 109 DCHECK(!op->GeneratesRegister()); |
| 110 DCHECK(!op->IsDoubleRegister()); | 110 DCHECK(!op->IsDoubleRegister()); |
| 111 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); | 111 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); |
| 112 // The linkage computes where all spill slots are located. | 112 // The linkage computes where all spill slots are located. |
| 113 FrameOffset offset = linkage()->GetFrameOffset( | 113 FrameOffset offset = linkage()->GetFrameOffset( |
| 114 AllocatedOperand::cast(op)->index(), frame(), 0); | 114 AllocatedOperand::cast(op)->index(), frame(), 0); |
| 115 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); | 115 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); |
| 116 } | 116 } |
| 117 }; | 117 }; |
| 118 | 118 |
| 119 | 119 |
| 120 static inline bool HasRegisterInput(Instruction* instr, size_t index) { | 120 static inline bool HasRegisterInput(Instruction* instr, size_t index) { |
| 121 return instr->InputAt(index)->IsRegister(); | 121 return instr->InputAt(index)->GeneratesRegister(); |
| 122 } | 122 } |
| 123 | 123 |
| 124 | 124 |
| 125 namespace { | 125 namespace { |
| 126 | 126 |
| 127 class OutOfLineLoadSingle final : public OutOfLineCode { | 127 class OutOfLineLoadSingle final : public OutOfLineCode { |
| 128 public: | 128 public: |
| 129 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result) | 129 OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result) |
| 130 : OutOfLineCode(gen), result_(result) {} | 130 : OutOfLineCode(gen), result_(result) {} |
| 131 | 131 |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 return kNoFPUCondition; | 296 return kNoFPUCondition; |
| 297 } | 297 } |
| 298 | 298 |
| 299 } // namespace | 299 } // namespace |
| 300 | 300 |
| 301 | 301 |
| 302 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \ | 302 #define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \ |
| 303 do { \ | 303 do { \ |
| 304 auto result = i.Output##width##Register(); \ | 304 auto result = i.Output##width##Register(); \ |
| 305 auto ool = new (zone()) OutOfLineLoad##width(this, result); \ | 305 auto ool = new (zone()) OutOfLineLoad##width(this, result); \ |
| 306 if (instr->InputAt(0)->IsRegister()) { \ | 306 if (instr->InputAt(0)->GeneratesRegister()) { \ |
| 307 auto offset = i.InputRegister(0); \ | 307 auto offset = i.InputRegister(0); \ |
| 308 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ | 308 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ |
| 309 __ addu(at, i.InputRegister(2), offset); \ | 309 __ addu(at, i.InputRegister(2), offset); \ |
| 310 __ asm_instr(result, MemOperand(at, 0)); \ | 310 __ asm_instr(result, MemOperand(at, 0)); \ |
| 311 } else { \ | 311 } else { \ |
| 312 auto offset = i.InputOperand(0).immediate(); \ | 312 auto offset = i.InputOperand(0).immediate(); \ |
| 313 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ | 313 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ |
| 314 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ | 314 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ |
| 315 } \ | 315 } \ |
| 316 __ bind(ool->exit()); \ | 316 __ bind(ool->exit()); \ |
| 317 } while (0) | 317 } while (0) |
| 318 | 318 |
| 319 | 319 |
| 320 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ | 320 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ |
| 321 do { \ | 321 do { \ |
| 322 auto result = i.OutputRegister(); \ | 322 auto result = i.OutputRegister(); \ |
| 323 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \ | 323 auto ool = new (zone()) OutOfLineLoadInteger(this, result); \ |
| 324 if (instr->InputAt(0)->IsRegister()) { \ | 324 if (instr->InputAt(0)->GeneratesRegister()) { \ |
| 325 auto offset = i.InputRegister(0); \ | 325 auto offset = i.InputRegister(0); \ |
| 326 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ | 326 __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \ |
| 327 __ addu(at, i.InputRegister(2), offset); \ | 327 __ addu(at, i.InputRegister(2), offset); \ |
| 328 __ asm_instr(result, MemOperand(at, 0)); \ | 328 __ asm_instr(result, MemOperand(at, 0)); \ |
| 329 } else { \ | 329 } else { \ |
| 330 auto offset = i.InputOperand(0).immediate(); \ | 330 auto offset = i.InputOperand(0).immediate(); \ |
| 331 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ | 331 __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset)); \ |
| 332 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ | 332 __ asm_instr(result, MemOperand(i.InputRegister(2), offset)); \ |
| 333 } \ | 333 } \ |
| 334 __ bind(ool->exit()); \ | 334 __ bind(ool->exit()); \ |
| 335 } while (0) | 335 } while (0) |
| 336 | 336 |
| 337 | 337 |
| 338 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \ | 338 #define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \ |
| 339 do { \ | 339 do { \ |
| 340 Label done; \ | 340 Label done; \ |
| 341 if (instr->InputAt(0)->IsRegister()) { \ | 341 if (instr->InputAt(0)->GeneratesRegister()) { \ |
| 342 auto offset = i.InputRegister(0); \ | 342 auto offset = i.InputRegister(0); \ |
| 343 auto value = i.Input##width##Register(2); \ | 343 auto value = i.Input##width##Register(2); \ |
| 344 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ | 344 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ |
| 345 __ addu(at, i.InputRegister(3), offset); \ | 345 __ addu(at, i.InputRegister(3), offset); \ |
| 346 __ asm_instr(value, MemOperand(at, 0)); \ | 346 __ asm_instr(value, MemOperand(at, 0)); \ |
| 347 } else { \ | 347 } else { \ |
| 348 auto offset = i.InputOperand(0).immediate(); \ | 348 auto offset = i.InputOperand(0).immediate(); \ |
| 349 auto value = i.Input##width##Register(2); \ | 349 auto value = i.Input##width##Register(2); \ |
| 350 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ | 350 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ |
| 351 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ | 351 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ |
| 352 } \ | 352 } \ |
| 353 __ bind(&done); \ | 353 __ bind(&done); \ |
| 354 } while (0) | 354 } while (0) |
| 355 | 355 |
| 356 | 356 |
| 357 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ | 357 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ |
| 358 do { \ | 358 do { \ |
| 359 Label done; \ | 359 Label done; \ |
| 360 if (instr->InputAt(0)->IsRegister()) { \ | 360 if (instr->InputAt(0)->GeneratesRegister()) { \ |
| 361 auto offset = i.InputRegister(0); \ | 361 auto offset = i.InputRegister(0); \ |
| 362 auto value = i.InputRegister(2); \ | 362 auto value = i.InputRegister(2); \ |
| 363 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ | 363 __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \ |
| 364 __ addu(at, i.InputRegister(3), offset); \ | 364 __ addu(at, i.InputRegister(3), offset); \ |
| 365 __ asm_instr(value, MemOperand(at, 0)); \ | 365 __ asm_instr(value, MemOperand(at, 0)); \ |
| 366 } else { \ | 366 } else { \ |
| 367 auto offset = i.InputOperand(0).immediate(); \ | 367 auto offset = i.InputOperand(0).immediate(); \ |
| 368 auto value = i.InputRegister(2); \ | 368 auto value = i.InputRegister(2); \ |
| 369 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ | 369 __ Branch(&done, ls, i.InputRegister(1), Operand(offset)); \ |
| 370 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ | 370 __ asm_instr(value, MemOperand(i.InputRegister(3), offset)); \ |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 case kMipsOr: | 546 case kMipsOr: |
| 547 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); | 547 __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
| 548 break; | 548 break; |
| 549 case kMipsXor: | 549 case kMipsXor: |
| 550 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); | 550 __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
| 551 break; | 551 break; |
| 552 case kMipsClz: | 552 case kMipsClz: |
| 553 __ Clz(i.OutputRegister(), i.InputRegister(0)); | 553 __ Clz(i.OutputRegister(), i.InputRegister(0)); |
| 554 break; | 554 break; |
| 555 case kMipsShl: | 555 case kMipsShl: |
| 556 if (instr->InputAt(1)->IsRegister()) { | 556 if (instr->InputAt(1)->GeneratesRegister()) { |
| 557 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); | 557 __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
| 558 } else { | 558 } else { |
| 559 int32_t imm = i.InputOperand(1).immediate(); | 559 int32_t imm = i.InputOperand(1).immediate(); |
| 560 __ sll(i.OutputRegister(), i.InputRegister(0), imm); | 560 __ sll(i.OutputRegister(), i.InputRegister(0), imm); |
| 561 } | 561 } |
| 562 break; | 562 break; |
| 563 case kMipsShr: | 563 case kMipsShr: |
| 564 if (instr->InputAt(1)->IsRegister()) { | 564 if (instr->InputAt(1)->GeneratesRegister()) { |
| 565 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); | 565 __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
| 566 } else { | 566 } else { |
| 567 int32_t imm = i.InputOperand(1).immediate(); | 567 int32_t imm = i.InputOperand(1).immediate(); |
| 568 __ srl(i.OutputRegister(), i.InputRegister(0), imm); | 568 __ srl(i.OutputRegister(), i.InputRegister(0), imm); |
| 569 } | 569 } |
| 570 break; | 570 break; |
| 571 case kMipsSar: | 571 case kMipsSar: |
| 572 if (instr->InputAt(1)->IsRegister()) { | 572 if (instr->InputAt(1)->GeneratesRegister()) { |
| 573 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); | 573 __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); |
| 574 } else { | 574 } else { |
| 575 int32_t imm = i.InputOperand(1).immediate(); | 575 int32_t imm = i.InputOperand(1).immediate(); |
| 576 __ sra(i.OutputRegister(), i.InputRegister(0), imm); | 576 __ sra(i.OutputRegister(), i.InputRegister(0), imm); |
| 577 } | 577 } |
| 578 break; | 578 break; |
| 579 case kMipsRor: | 579 case kMipsRor: |
| 580 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); | 580 __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); |
| 581 break; | 581 break; |
| 582 case kMipsTst: | 582 case kMipsTst: |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1167 __ Ret(); | 1167 __ Ret(); |
| 1168 } | 1168 } |
| 1169 } | 1169 } |
| 1170 | 1170 |
| 1171 | 1171 |
| 1172 void CodeGenerator::AssembleMove(InstructionOperand* source, | 1172 void CodeGenerator::AssembleMove(InstructionOperand* source, |
| 1173 InstructionOperand* destination) { | 1173 InstructionOperand* destination) { |
| 1174 MipsOperandConverter g(this, NULL); | 1174 MipsOperandConverter g(this, NULL); |
| 1175 // Dispatch on the source and destination operand kinds. Not all | 1175 // Dispatch on the source and destination operand kinds. Not all |
| 1176 // combinations are possible. | 1176 // combinations are possible. |
| 1177 if (source->IsRegister()) { | 1177 if (source->GeneratesRegister()) { |
| 1178 DCHECK(destination->IsRegister() || destination->IsStackSlot()); | 1178 DCHECK(destination->GeneratesRegister() || destination->IsStackSlot()); |
| 1179 Register src = g.ToRegister(source); | 1179 Register src = g.ToRegister(source); |
| 1180 if (destination->IsRegister()) { | 1180 if (destination->GeneratesRegister()) { |
| 1181 __ mov(g.ToRegister(destination), src); | 1181 __ mov(g.ToRegister(destination), src); |
| 1182 } else { | 1182 } else { |
| 1183 __ sw(src, g.ToMemOperand(destination)); | 1183 __ sw(src, g.ToMemOperand(destination)); |
| 1184 } | 1184 } |
| 1185 } else if (source->IsStackSlot()) { | 1185 } else if (source->IsStackSlot()) { |
| 1186 DCHECK(destination->IsRegister() || destination->IsStackSlot()); | 1186 DCHECK(destination->GeneratesRegister() || destination->IsStackSlot()); |
| 1187 MemOperand src = g.ToMemOperand(source); | 1187 MemOperand src = g.ToMemOperand(source); |
| 1188 if (destination->IsRegister()) { | 1188 if (destination->GeneratesRegister()) { |
| 1189 __ lw(g.ToRegister(destination), src); | 1189 __ lw(g.ToRegister(destination), src); |
| 1190 } else { | 1190 } else { |
| 1191 Register temp = kScratchReg; | 1191 Register temp = kScratchReg; |
| 1192 __ lw(temp, src); | 1192 __ lw(temp, src); |
| 1193 __ sw(temp, g.ToMemOperand(destination)); | 1193 __ sw(temp, g.ToMemOperand(destination)); |
| 1194 } | 1194 } |
| 1195 } else if (source->IsConstant()) { | 1195 } else if (source->IsConstant()) { |
| 1196 Constant src = g.ToConstant(source); | 1196 Constant src = g.ToConstant(source); |
| 1197 if (destination->IsRegister() || destination->IsStackSlot()) { | 1197 if (destination->GeneratesRegister() || destination->IsStackSlot()) { |
| 1198 Register dst = | 1198 Register dst = destination->GeneratesRegister() |
| 1199 destination->IsRegister() ? g.ToRegister(destination) : kScratchReg; | 1199 ? g.ToRegister(destination) |
| 1200 : kScratchReg; |
| 1200 switch (src.type()) { | 1201 switch (src.type()) { |
| 1201 case Constant::kInt32: | 1202 case Constant::kInt32: |
| 1202 __ li(dst, Operand(src.ToInt32())); | 1203 __ li(dst, Operand(src.ToInt32())); |
| 1203 break; | 1204 break; |
| 1204 case Constant::kFloat32: | 1205 case Constant::kFloat32: |
| 1205 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED)); | 1206 __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED)); |
| 1206 break; | 1207 break; |
| 1207 case Constant::kInt64: | 1208 case Constant::kInt64: |
| 1208 UNREACHABLE(); | 1209 UNREACHABLE(); |
| 1209 break; | 1210 break; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1273 UNREACHABLE(); | 1274 UNREACHABLE(); |
| 1274 } | 1275 } |
| 1275 } | 1276 } |
| 1276 | 1277 |
| 1277 | 1278 |
| 1278 void CodeGenerator::AssembleSwap(InstructionOperand* source, | 1279 void CodeGenerator::AssembleSwap(InstructionOperand* source, |
| 1279 InstructionOperand* destination) { | 1280 InstructionOperand* destination) { |
| 1280 MipsOperandConverter g(this, NULL); | 1281 MipsOperandConverter g(this, NULL); |
| 1281 // Dispatch on the source and destination operand kinds. Not all | 1282 // Dispatch on the source and destination operand kinds. Not all |
| 1282 // combinations are possible. | 1283 // combinations are possible. |
| 1283 if (source->IsRegister()) { | 1284 if (source->GeneratesRegister()) { |
| 1284 // Register-register. | 1285 // Register-register. |
| 1285 Register temp = kScratchReg; | 1286 Register temp = kScratchReg; |
| 1286 Register src = g.ToRegister(source); | 1287 Register src = g.ToRegister(source); |
| 1287 if (destination->IsRegister()) { | 1288 if (destination->GeneratesRegister()) { |
| 1288 Register dst = g.ToRegister(destination); | 1289 Register dst = g.ToRegister(destination); |
| 1289 __ Move(temp, src); | 1290 __ Move(temp, src); |
| 1290 __ Move(src, dst); | 1291 __ Move(src, dst); |
| 1291 __ Move(dst, temp); | 1292 __ Move(dst, temp); |
| 1292 } else { | 1293 } else { |
| 1293 DCHECK(destination->IsStackSlot()); | 1294 DCHECK(destination->IsStackSlot()); |
| 1294 MemOperand dst = g.ToMemOperand(destination); | 1295 MemOperand dst = g.ToMemOperand(destination); |
| 1295 __ mov(temp, src); | 1296 __ mov(temp, src); |
| 1296 __ lw(src, dst); | 1297 __ lw(src, dst); |
| 1297 __ sw(temp, dst); | 1298 __ sw(temp, dst); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 } | 1374 } |
| 1374 } | 1375 } |
| 1375 } | 1376 } |
| 1376 } | 1377 } |
| 1377 | 1378 |
| 1378 #undef __ | 1379 #undef __ |
| 1379 | 1380 |
| 1380 } // namespace compiler | 1381 } // namespace compiler |
| 1381 } // namespace internal | 1382 } // namespace internal |
| 1382 } // namespace v8 | 1383 } // namespace v8 |
| OLD | NEW |