1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_MIPS
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h"
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/ic.h"
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ic/stub-cache.h"
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 {
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal {
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochCondition CompareIC::ComputeCondition(Token::Value op) {
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  switch (op) {
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case Token::EQ_STRICT:
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case Token::EQ:
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return eq;
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case Token::LT:
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return lt;
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case Token::GT:
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return gt;
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case Token::LTE:
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return le;
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case Token::GTE:
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return ge;
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    default:
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      UNREACHABLE();
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return kNoCondition;
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochbool CompareIC::HasInlinedSmiCode(Address address) {
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The address of the instruction following the call.
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address andi_instruction_address =
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      address + Assembler::kCallTargetAddressOffset;
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // If the instruction following the call is not a andi at, rx, #yyy, nothing
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // was inlined.
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Instr instr = Assembler::instr_at(andi_instruction_address);
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return Assembler::IsAndImmediate(instr) &&
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch         Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid PatchInlinedSmiCode(Isolate* isolate, Address address,
49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                         InlinedSmiCheck check) {
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address andi_instruction_address =
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      address + Assembler::kCallTargetAddressOffset;
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // If the instruction following the call is not a andi at, rx, #yyy, nothing
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // was inlined.
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Instr instr = Assembler::instr_at(andi_instruction_address);
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!(Assembler::IsAndImmediate(instr) &&
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return;
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The delta to the start of the map check instruction and the
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // condition code uses at the patched jump.
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int delta = Assembler::GetImmediate16(instr);
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  delta += Assembler::GetRs(instr) * kImm16Mask;
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // signals that nothing was inlined.
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (delta == 0) {
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return;
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (FLAG_trace_ic) {
7262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch    LOG(isolate, PatchIC(address, andi_instruction_address, delta));
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Address patch_address =
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      andi_instruction_address - delta * Instruction::kInstrSize;
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Instr instr_at_patch = Assembler::instr_at(patch_address);
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // This is patching a conditional "jump if not smi/jump if smi" site.
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Enabling by changing from
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //   andi at, rx, 0
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //   Branch <target>, eq, at, Operand(zero_reg)
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // to:
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //   andi at, rx, #kSmiTagMask
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  //   Branch <target>, ne, at, Operand(zero_reg)
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // and vice-versa to be disabled again.
86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CodePatcher patcher(isolate, patch_address, 2);
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (check == ENABLE_INLINED_SMI_CHECK) {
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(Assembler::IsAndImmediate(instr_at_patch));
90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    DCHECK_EQ(0u, Assembler::GetImmediate16(instr_at_patch));
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    patcher.masm()->andi(at, reg, kSmiTagMask);
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    DCHECK_EQ(check, DISABLE_INLINED_SMI_CHECK);
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(Assembler::IsAndImmediate(instr_at_patch));
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    patcher.masm()->andi(at, reg, 0);
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Instr branch_instr =
98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Assembler::instr_at(patch_address + Instruction::kInstrSize);
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(Assembler::IsBranch(branch_instr));
100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  uint32_t opcode = Assembler::GetOpcodeField(branch_instr);
102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Currently only the 'eq' and 'ne' cond values are supported and the simple
103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // branch instructions and their r6 variants (with opcode being the branch
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // type). There are some special cases (see Assembler::IsBranch()) so
105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // extending this would be tricky.
106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK(opcode == BEQ ||    // BEQ
107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         opcode == BNE ||    // BNE
108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         opcode == POP10 ||  // BEQC
109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         opcode == POP30 ||  // BNEC
110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         opcode == POP66 ||  // BEQZC
111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         opcode == POP76);   // BNEZC
112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  switch (opcode) {
113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case BEQ:
114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      opcode = BNE;  // change BEQ to BNE.
115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case POP10:
117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      opcode = POP30;  // change BEQC to BNEC.
118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case POP66:
120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      opcode = POP76;  // change BEQZC to BNEZC.
121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case BNE:
123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      opcode = BEQ;  // change BNE to BEQ.
124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
125014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case POP30:
126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      opcode = POP10;  // change BNEC to BEQC.
127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case POP76:
129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      opcode = POP66;  // change BNEZC to BEQZC.
130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    default:
132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      UNIMPLEMENTED();
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  patcher.ChangeBranchCondition(branch_instr, opcode);
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif  // V8_TARGET_ARCH_MIPS
140