Chromium Code Reviews| Index: src/mips64/simulator-mips64.cc |
| diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc |
| index d3fcb4a7a3e8798815aeacfe0412bf1a86b3c42c..19f70758d0d70f6479a2805582a318dfcc06f725 100644 |
| --- a/src/mips64/simulator-mips64.cc |
| +++ b/src/mips64/simulator-mips64.cc |
| @@ -146,7 +146,7 @@ void MipsDebugger::Stop(Instruction* instr) { |
| #else // GENERATED_CODE_COVERAGE |
| -#define UNSUPPORTED() printf("Unsupported instruction.\n"); |
| +#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n"); |
| static void InitializeCoverage() {} |
| @@ -4051,27 +4051,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
| } |
| -// Branch instructions common part. |
| -#define BranchAndLinkHelper(do_branch) \ |
| - execute_branch_delay_instruction = true; \ |
| - if (do_branch) { \ |
| - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \ |
| - set_register(31, current_pc + kBranchReturnOffset); \ |
| - } else { \ |
| - next_pc = current_pc + kBranchReturnOffset; \ |
| - } |
| - |
| - |
| -#define BranchHelper(do_branch) \ |
| - execute_branch_delay_instruction = true; \ |
| - if (do_branch) { \ |
| - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \ |
| - } else { \ |
| - next_pc = current_pc + kBranchReturnOffset; \ |
| - } |
| - |
| - |
| -// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq). |
| +// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc). |
| void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| // Instruction fields. |
| Opcode op = instr->OpcodeFieldRaw(); |
| @@ -4082,21 +4062,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| int64_t rt = get_register(rt_reg); |
| int16_t imm16 = instr->Imm16Value(); |
| int32_t imm18 = instr->Imm18Value(); |
| - int32_t imm21 = instr->Imm21Value(); |
| - int32_t imm26 = instr->Imm26Value(); |
| int32_t ft_reg = instr->FtValue(); // Destination register. |
| - int64_t ft = get_fpu_register(ft_reg); |
| // Zero extended immediate. |
| uint64_t oe_imm16 = 0xffff & imm16; |
| // Sign extended immediate. |
| int64_t se_imm16 = imm16; |
| int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0); |
| - int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0); |
| - // Get current pc. |
| - int64_t current_pc = get_pc(); |
| // Next pc. |
| int64_t next_pc = bad_ra; |
| @@ -4111,7 +4085,56 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| // Alignment for 32-bit integers used in LWL, LWR, etc. |
| const int kInt32AlignmentMask = sizeof(uint32_t) - 1; |
| - // ---------- Configuration (and execution for REGIMM). |
| + // Branch instructions common part. |
| + auto BranchAndLinkHelper = [this, instr, &next_pc, |
| + &execute_branch_delay_instruction]( |
| + bool do_branch) { |
| + execute_branch_delay_instruction = true; |
| + int64_t current_pc = get_pc(); |
| + if (do_branch) { |
| + int16_t imm16 = instr->Imm16Value(); |
| + next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; |
| + set_register(31, current_pc + 2 * Instruction::kInstrSize); |
| + } else { |
| + next_pc = current_pc + 2 * Instruction::kInstrSize; |
| + } |
| + }; |
| + |
| + auto BranchHelper = [this, instr, &next_pc, |
| + &execute_branch_delay_instruction](bool do_branch) { |
| + execute_branch_delay_instruction = true; |
| + int64_t current_pc = get_pc(); |
| + if (do_branch) { |
| + int16_t imm16 = instr->Imm16Value(); |
| + next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; |
| + } else { |
| + next_pc = current_pc + 2 * Instruction::kInstrSize; |
| + } |
| + }; |
| + |
| + auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch, |
| + int bits) { |
| + int64_t current_pc = get_pc(); |
| + CheckForbiddenSlot(current_pc); |
| + if (do_branch) { |
| + int32_t imm = instr->ImmValue(bits); |
| + imm <<= 32 - bits; |
| + imm >>= 32 - bits; |
| + next_pc = current_pc + (imm << 2) + Instruction::kInstrSize; |
| + set_register(31, current_pc + Instruction::kInstrSize); |
| + } |
| + }; |
| + |
| + auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) { |
| + int64_t current_pc = get_pc(); |
| + CheckForbiddenSlot(current_pc); |
| + if (do_branch) { |
| + int32_t imm = instr->ImmValue(bits); |
| + imm <<= 32 - bits; |
| + imm >>= 32 - bits; |
| + next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize; |
| + } |
| + }; |
|
balazs.kilvady
2016/01/04 15:30:38
Add a newline, please.
|
| switch (op) { |
| // ------------- COP1. Coprocessor instructions. |
| case COP1: |
| @@ -4121,32 +4144,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| uint32_t fcsr_cc = get_fcsr_condition_bit(cc); |
| uint32_t cc_value = test_fcsr_bit(fcsr_cc); |
| bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; |
| - execute_branch_delay_instruction = true; |
| - // Set next_pc. |
| - if (do_branch) { |
| - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; |
| - } else { |
| - next_pc = current_pc + kBranchReturnOffset; |
| - } |
| + BranchHelper(do_branch); |
| break; |
| } |
| case BC1EQZ: |
| - execute_branch_delay_instruction = true; |
| - // Set next_pc. |
| - if (!(ft & 0x1)) { |
| - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; |
| - } else { |
| - next_pc = current_pc + kBranchReturnOffset; |
| - } |
| + BranchHelper(!(get_fpu_register(ft_reg) & 0x1)); |
| break; |
| case BC1NEZ: |
| - execute_branch_delay_instruction = true; |
| - // Set next_pc. |
| - if (ft & 0x1) { |
| - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; |
| - } else { |
| - next_pc = current_pc + kBranchReturnOffset; |
| - } |
| + BranchHelper(get_fpu_register(ft_reg) & 0x1); |
| break; |
| default: |
| UNREACHABLE(); |
| @@ -4186,55 +4191,158 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| case BNE: |
| BranchHelper(rs != rt); |
| break; |
| - case BLEZ: |
| - BranchHelper(rs <= 0); |
| - break; |
| - case BGTZ: |
| - BranchHelper(rs > 0); |
| - break; |
| - case POP66: { |
| - if (rs_reg) { // BEQZC |
| - int32_t se_imm21 = |
| - static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits)); |
| - se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits); |
| - if (rs == 0) |
| - next_pc = current_pc + 4 + (se_imm21 << 2); |
| - else |
| - next_pc = current_pc + 4; |
| + case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6) |
| + if (kArchVariant == kMips64r6) { |
| + if (rt_reg != 0) { |
| + if (rs_reg == 0) { // BLEZALC |
| + BranchAndLinkCompactHelper(rt <= 0, 16); |
| + } else { |
| + if (rs_reg == rt_reg) { // BGEZALC |
| + BranchAndLinkCompactHelper(rt >= 0, 16); |
| + } else { // BGEUC |
| + BranchCompactHelper( |
| + static_cast<uint64_t>(rs) >= static_cast<uint64_t>(rt), 16); |
| + } |
| + } |
| + } else { // BLEZ |
| + BranchHelper(rs <= 0); |
| + } |
| + } else { // BLEZ |
| + BranchHelper(rs <= 0); |
| + } |
| + break; |
| + case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6) |
| + if (kArchVariant == kMips64r6) { |
| + if (rt_reg != 0) { |
| + if (rs_reg == 0) { // BGTZALC |
| + BranchAndLinkCompactHelper(rt > 0, 16); |
| + } else { |
| + if (rt_reg == rs_reg) { // BLTZALC |
| + BranchAndLinkCompactHelper(rt < 0, 16); |
| + } else { // BLTUC |
| + BranchCompactHelper( |
| + static_cast<uint64_t>(rs) < static_cast<uint64_t>(rt), 16); |
| + } |
| + } |
| + } else { // BGTZ |
| + BranchHelper(rs > 0); |
| + } |
| + } else { // BGTZ |
| + BranchHelper(rs > 0); |
| + } |
| + break; |
| + case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6) |
| + if (kArchVariant == kMips64r6) { |
| + if (rt_reg != 0) { |
| + if (rs_reg == 0) { // BLEZC |
| + BranchCompactHelper(rt <= 0, 16); |
| + } else { |
| + if (rs_reg == rt_reg) { // BGEZC |
| + BranchCompactHelper(rt >= 0, 16); |
| + } else { // BGEC/BLEC |
| + BranchCompactHelper(rs >= rt, 16); |
| + } |
| + } |
| + } |
| + } else { // BLEZL |
| + BranchAndLinkHelper(rs <= 0); |
| + } |
| + break; |
| + case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6) |
| + if (kArchVariant == kMips64r6) { |
| + if (rt_reg != 0) { |
| + if (rs_reg == 0) { // BGTZC |
| + BranchCompactHelper(rt > 0, 16); |
| + } else { |
| + if (rs_reg == rt_reg) { // BLTZC |
| + BranchCompactHelper(rt < 0, 16); |
| + } else { // BLTC/BGTC |
| + BranchCompactHelper(rs < rt, 16); |
| + } |
| + } |
| + } |
| + } else { // BGTZL |
| + BranchAndLinkHelper(rs > 0); |
| + } |
| + break; |
| + case POP66: // BEQZC, JIC |
| + if (rs_reg != 0) { // BEQZC |
| + BranchCompactHelper(rs == 0, 21); |
| } else { // JIC |
| + CheckForbiddenSlot(get_pc()); |
|
balazs.kilvady
2016/01/04 15:30:38
Remove this check, JIC has no forbidden slot issue
|
| next_pc = rt + imm16; |
| } |
| break; |
| - } |
| - case BC: { |
| - next_pc = current_pc + 4 + (se_imm26 << 2); |
| - set_pc(next_pc); |
| - pc_modified_ = true; |
| + case POP76: // BNEZC, JIALC |
| + if (rs_reg != 0) { // BNEZC |
| + BranchCompactHelper(rs != 0, 21); |
| + } else { // JIALC |
| + int64_t current_pc = get_pc(); |
| + CheckForbiddenSlot(current_pc); |
|
balazs.kilvady
2016/01/04 15:30:38
Remove this check, JIALC has no forbidden slot iss
|
| + set_register(31, current_pc + Instruction::kInstrSize); |
| + next_pc = rt + imm16; |
| + } |
| break; |
| - } |
| - case BALC: { |
| - set_register(31, current_pc + 4); |
| - next_pc = current_pc + 4 + (se_imm26 << 2); |
| - set_pc(next_pc); |
| - pc_modified_ = true; |
| + case BC: |
| + BranchCompactHelper(true, 26); |
| break; |
| - } |
| - // ------------- Arithmetic instructions. |
| - case ADDI: |
| - case DADDI: |
| - if (HaveSameSign(rs, se_imm16)) { |
| - if (rs > 0) { |
| - if (rs > Registers::kMaxValue - se_imm16) { |
| - SignalException(kIntegerOverflow); |
| + case BALC: |
| + BranchAndLinkCompactHelper(true, 26); |
| + break; |
| + case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6) |
| + if (kArchVariant == kMips64r6) { |
| + if (rs_reg >= rt_reg) { // BOVC |
| + if (HaveSameSign(rs, rt)) { |
| + if (rs > 0) { |
| + BranchCompactHelper(rs > Registers::kMaxValue - rt, 16); |
| + } else if (rs < 0) { |
| + BranchCompactHelper(rs < Registers::kMinValue - rt, 16); |
| + } |
| } |
| - } else if (rs < 0) { |
| - if (rs < Registers::kMinValue - se_imm16) { |
| - SignalException(kIntegerUnderflow); |
| + } else { |
| + if (rs_reg == 0) { // BEQZALC |
| + BranchAndLinkCompactHelper(rt == 0, 16); |
| + } else { // BEQC |
| + BranchCompactHelper(rt == rs, 16); |
| } |
| } |
| + } else { // ADDI |
| + if (HaveSameSign(rs, se_imm16)) { |
| + if (rs > 0) { |
| + if (rs <= Registers::kMaxValue - se_imm16) { |
| + SignalException(kIntegerOverflow); |
| + } |
| + } else if (rs < 0) { |
| + if (rs >= Registers::kMinValue - se_imm16) { |
| + SignalException(kIntegerUnderflow); |
| + } |
| + } |
| + } |
| + SetResult(rt_reg, rs + se_imm16); |
| } |
| - SetResult(rt_reg, rs + se_imm16); |
| break; |
| + case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6) |
| + if (kArchVariant == kMips64r6) { |
| + if (rs_reg >= rt_reg) { // BNVC |
| + if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) { |
| + BranchCompactHelper(true, 16); |
| + } else { |
| + if (rs > 0) { |
| + BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16); |
| + } else if (rs < 0) { |
| + BranchCompactHelper(rs >= Registers::kMinValue - rt, 16); |
| + } |
| + } |
| + } else { |
| + if (rs_reg == 0) { // BNEZALC |
| + BranchAndLinkCompactHelper(rt != 0, 16); |
| + } else { // BNEC |
| + BranchCompactHelper(rt != rs, 16); |
| + } |
| + } |
| + } |
| + break; |
| + // ------------- Arithmetic instructions. |
| case ADDIU: { |
| int32_t alu32_out = static_cast<int32_t>(rs + se_imm16); |
| // Sign-extend result of 32bit operation into 64bit register. |
| @@ -4369,22 +4477,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| case SDC1: |
| WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr); |
| break; |
| - // ------------- JIALC and BNEZC instructions. |
| - case POP76: { |
| - // Next pc. |
| - next_pc = rt + se_imm16; |
| - // The instruction after the jump is NOT executed. |
| - uint16_t pc_increment = Instruction::kInstrSize; |
| - if (instr->IsLinkingInstruction()) { |
| - set_register(31, current_pc + pc_increment); |
| - } |
| - set_pc(next_pc); |
| - pc_modified_ = true; |
| - break; |
| - } |
| // ------------- PC-Relative instructions. |
| case PCREL: { |
| // rt field: checking 5-bits. |
| + int32_t imm21 = instr->Imm21Value(); |
| + int64_t current_pc = get_pc(); |
| uint8_t rt = (imm21 >> kImm16Bits); |
| switch (rt) { |
| case ALUIPC: |
| @@ -4454,7 +4551,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| // We don't check for end_sim_pc. First it should not be met as the current |
| // pc is valid. Secondly a jump should always execute its branch delay slot. |
| Instruction* branch_delay_instr = |
| - reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize); |
| + reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize); |
| BranchDelayInstructionDecode(branch_delay_instr); |
| } |
| @@ -4464,9 +4561,6 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { |
| } |
| } |
| -#undef BranchHelper |
| -#undef BranchAndLinkHelper |
| - |
| // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). |
| void Simulator::DecodeTypeJump(Instruction* instr) { |
| @@ -4557,7 +4651,7 @@ void Simulator::Execute() { |
| while (program_counter != end_sim_pc) { |
| Instruction* instr = reinterpret_cast<Instruction*>(program_counter); |
| icount_++; |
| - if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) { |
| + if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) { |
| MipsDebugger dbg(this); |
| dbg.Debug(); |
| } else { |