blob: 3eba42f0dca179face77674d737dc3b2501a367c [file] [log] [blame]
Ben Murdoch097c5b22016-05-18 11:27:45 +01001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/interpreter/register-translator.h"
6
7#include "src/interpreter/bytecode-array-builder.h"
8
9namespace v8 {
10namespace internal {
11namespace interpreter {
12
13RegisterTranslator::RegisterTranslator(RegisterMover* mover)
14 : mover_(mover),
15 emitting_moves_(false),
16 window_registers_count_(0),
17 output_moves_count_(0) {}
18
19void RegisterTranslator::TranslateInputRegisters(Bytecode bytecode,
20 uint32_t* raw_operands,
21 int raw_operand_count) {
22 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), raw_operand_count);
23 if (!emitting_moves_) {
24 emitting_moves_ = true;
25 DCHECK_EQ(window_registers_count_, 0);
26 int register_bitmap = Bytecodes::GetRegisterOperandBitmap(bytecode);
27 for (int i = 0; i < raw_operand_count; i++) {
28 if ((register_bitmap & (1 << i)) == 0) {
29 continue;
30 }
31 Register in_reg = Register::FromRawOperand(raw_operands[i]);
32 Register out_reg = TranslateAndMove(bytecode, i, in_reg);
33 raw_operands[i] = out_reg.ToRawOperand();
34 }
35 window_registers_count_ = 0;
36 emitting_moves_ = false;
37 } else {
38 // When the register translator is translating registers, it will
39 // cause the bytecode generator to emit moves on it's behalf. This
40 // path is reached by these moves.
41 DCHECK(bytecode == Bytecode::kMovWide && raw_operand_count == 2 &&
42 Register::FromRawOperand(raw_operands[0]).is_valid() &&
43 Register::FromRawOperand(raw_operands[1]).is_valid());
44 }
45}
46
47Register RegisterTranslator::TranslateAndMove(Bytecode bytecode,
48 int operand_index, Register reg) {
49 if (FitsInReg8Operand(reg)) {
50 return reg;
51 }
52
53 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index);
54 OperandSize operand_size = Bytecodes::SizeOfOperand(operand_type);
55 if (operand_size == OperandSize::kShort) {
56 CHECK(FitsInReg16Operand(reg));
57 return Translate(reg);
58 }
59
60 CHECK((operand_type == OperandType::kReg8 ||
61 operand_type == OperandType::kRegOut8) &&
62 RegisterIsMovableToWindow(bytecode, operand_index));
63 Register translated_reg = Translate(reg);
64 Register window_reg(kTranslationWindowStart + window_registers_count_);
65 window_registers_count_ += 1;
66 if (Bytecodes::IsRegisterInputOperandType(operand_type)) {
67 DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_type));
68 mover()->MoveRegisterUntranslated(translated_reg, window_reg);
69 } else if (Bytecodes::IsRegisterOutputOperandType(operand_type)) {
70 DCHECK_LT(output_moves_count_, kTranslationWindowLength);
71 output_moves_[output_moves_count_] =
72 std::make_pair(window_reg, translated_reg);
73 output_moves_count_ += 1;
74 } else {
75 UNREACHABLE();
76 }
77 return window_reg;
78}
79
80// static
81bool RegisterTranslator::RegisterIsMovableToWindow(Bytecode bytecode,
82 int operand_index) {
83 // By design, we only support moving individual registers. There
84 // should be wide variants of such bytecodes instead to avoid the
85 // need for a large translation window.
86 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index);
87 if (operand_type != OperandType::kReg8 &&
88 operand_type != OperandType::kRegOut8) {
89 return false;
90 } else if (operand_index + 1 == Bytecodes::NumberOfOperands(bytecode)) {
91 return true;
92 } else {
93 OperandType next_operand_type =
94 Bytecodes::GetOperandType(bytecode, operand_index + 1);
95 return (next_operand_type != OperandType::kRegCount8 &&
96 next_operand_type != OperandType::kRegCount16);
97 }
98}
99
100void RegisterTranslator::TranslateOutputRegisters() {
101 if (!emitting_moves_) {
102 emitting_moves_ = true;
103 while (output_moves_count_ > 0) {
104 output_moves_count_ -= 1;
105 mover()->MoveRegisterUntranslated(
106 output_moves_[output_moves_count_].first,
107 output_moves_[output_moves_count_].second);
108 }
109 emitting_moves_ = false;
110 }
111}
112
113// static
114Register RegisterTranslator::Translate(Register reg) {
115 if (reg.index() >= kTranslationWindowStart) {
116 return Register(reg.index() + kTranslationWindowLength);
117 } else {
118 return reg;
119 }
120}
121
122// static
123bool RegisterTranslator::InTranslationWindow(Register reg) {
124 return (reg.index() >= kTranslationWindowStart &&
125 reg.index() <= kTranslationWindowLimit);
126}
127
128// static
129Register RegisterTranslator::UntranslateRegister(Register reg) {
130 if (reg.index() >= kTranslationWindowStart) {
131 return Register(reg.index() - kTranslationWindowLength);
132 } else {
133 return reg;
134 }
135}
136
137// static
138int RegisterTranslator::DistanceToTranslationWindow(Register reg) {
139 return kTranslationWindowStart - reg.index();
140}
141
142// static
143bool RegisterTranslator::FitsInReg8Operand(Register reg) {
144 return reg.is_byte_operand() && reg.index() < kTranslationWindowStart;
145}
146
147// static
148bool RegisterTranslator::FitsInReg16Operand(Register reg) {
149 int max_index = Register::MaxRegisterIndex() - kTranslationWindowLength + 1;
150 return reg.is_short_operand() && reg.index() < max_index;
151}
152
153// static
154int RegisterTranslator::RegisterCountAdjustment(int register_count,
155 int parameter_count) {
156 if (register_count > kTranslationWindowStart) {
157 return kTranslationWindowLength;
158 } else if (parameter_count > 0) {
159 Register param0 = Register::FromParameterIndex(0, parameter_count);
160 if (!param0.is_byte_operand()) {
161 // TODO(oth): Number of parameters means translation is
162 // required, but the translation window location is such that
163 // some space is wasted. Hopefully a rare corner case, but could
164 // relocate window to limit waste.
165 return kTranslationWindowLimit + 1 - register_count;
166 }
167 }
168 return 0;
169}
170
171} // namespace interpreter
172} // namespace internal
173} // namespace v8