|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef jit_mips_Assembler_mips_h |
|
8 #define jit_mips_Assembler_mips_h |
|
9 |
|
10 #include "mozilla/ArrayUtils.h" |
|
11 #include "mozilla/Attributes.h" |
|
12 #include "mozilla/MathAlgorithms.h" |
|
13 |
|
14 #include "jit/CompactBuffer.h" |
|
15 #include "jit/IonCode.h" |
|
16 #include "jit/IonSpewer.h" |
|
17 #include "jit/mips/Architecture-mips.h" |
|
18 #include "jit/shared/Assembler-shared.h" |
|
19 #include "jit/shared/IonAssemblerBuffer.h" |
|
20 |
|
21 namespace js { |
|
22 namespace jit { |
|
23 |
|
24 static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero }; |
|
25 static MOZ_CONSTEXPR_VAR Register at = { Registers::at }; |
|
26 static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 }; |
|
27 static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 }; |
|
28 static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 }; |
|
29 static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 }; |
|
30 static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 }; |
|
31 static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 }; |
|
32 static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 }; |
|
33 static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 }; |
|
34 static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 }; |
|
35 static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 }; |
|
36 static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 }; |
|
37 static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 }; |
|
38 static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 }; |
|
39 static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 }; |
|
40 static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 }; |
|
41 static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 }; |
|
42 static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 }; |
|
43 static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 }; |
|
44 static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 }; |
|
45 static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 }; |
|
46 static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 }; |
|
47 static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 }; |
|
48 static MOZ_CONSTEXPR_VAR Register t8 = { Registers::t8 }; |
|
49 static MOZ_CONSTEXPR_VAR Register t9 = { Registers::t9 }; |
|
50 static MOZ_CONSTEXPR_VAR Register k0 = { Registers::k0 }; |
|
51 static MOZ_CONSTEXPR_VAR Register k1 = { Registers::k1 }; |
|
52 static MOZ_CONSTEXPR_VAR Register gp = { Registers::gp }; |
|
53 static MOZ_CONSTEXPR_VAR Register sp = { Registers::sp }; |
|
54 static MOZ_CONSTEXPR_VAR Register fp = { Registers::fp }; |
|
55 static MOZ_CONSTEXPR_VAR Register ra = { Registers::ra }; |
|
56 |
|
57 static MOZ_CONSTEXPR_VAR Register ScratchRegister = at; |
|
58 static MOZ_CONSTEXPR_VAR Register SecondScratchReg = t8; |
|
59 |
|
60 // Use arg reg from EnterJIT function as OsrFrameReg. |
|
61 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = a3; |
|
62 static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = s3; |
|
63 static MOZ_CONSTEXPR_VAR Register CallTempReg0 = t0; |
|
64 static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1; |
|
65 static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2; |
|
66 static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3; |
|
67 static MOZ_CONSTEXPR_VAR Register CallTempReg4 = t4; |
|
68 static MOZ_CONSTEXPR_VAR Register CallTempReg5 = t5; |
|
69 |
|
70 static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0; |
|
71 static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1; |
|
72 static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2; |
|
73 static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3; |
|
74 static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin |
|
75 static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin |
|
76 static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 }; |
|
77 static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); |
|
78 |
|
79 class ABIArgGenerator |
|
80 { |
|
81 unsigned usedArgSlots_; |
|
82 bool firstArgFloat; |
|
83 ABIArg current_; |
|
84 |
|
85 public: |
|
86 ABIArgGenerator(); |
|
87 ABIArg next(MIRType argType); |
|
88 ABIArg ¤t() { return current_; } |
|
89 |
|
90 uint32_t stackBytesConsumedSoFar() const { |
|
91 if (usedArgSlots_ <= 4) |
|
92 return 4 * sizeof(intptr_t); |
|
93 |
|
94 return usedArgSlots_ * sizeof(intptr_t); |
|
95 } |
|
96 |
|
97 static const Register NonArgReturnVolatileReg0; |
|
98 static const Register NonArgReturnVolatileReg1; |
|
99 }; |
|
100 |
|
101 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1; |
|
102 |
|
103 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg }; |
|
104 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; |
|
105 |
|
106 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = v1; |
|
107 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = v0; |
|
108 static MOZ_CONSTEXPR_VAR Register StackPointer = sp; |
|
109 static MOZ_CONSTEXPR_VAR Register FramePointer = fp; |
|
110 static MOZ_CONSTEXPR_VAR Register ReturnReg = v0; |
|
111 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 }; |
|
112 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 }; |
|
113 static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 }; |
|
114 |
|
115 static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::f30 }; |
|
116 |
|
117 static MOZ_CONSTEXPR_VAR FloatRegister f0 = {FloatRegisters::f0}; |
|
118 static MOZ_CONSTEXPR_VAR FloatRegister f2 = {FloatRegisters::f2}; |
|
119 static MOZ_CONSTEXPR_VAR FloatRegister f4 = {FloatRegisters::f4}; |
|
120 static MOZ_CONSTEXPR_VAR FloatRegister f6 = {FloatRegisters::f6}; |
|
121 static MOZ_CONSTEXPR_VAR FloatRegister f8 = {FloatRegisters::f8}; |
|
122 static MOZ_CONSTEXPR_VAR FloatRegister f10 = {FloatRegisters::f10}; |
|
123 static MOZ_CONSTEXPR_VAR FloatRegister f12 = {FloatRegisters::f12}; |
|
124 static MOZ_CONSTEXPR_VAR FloatRegister f14 = {FloatRegisters::f14}; |
|
125 static MOZ_CONSTEXPR_VAR FloatRegister f16 = {FloatRegisters::f16}; |
|
126 static MOZ_CONSTEXPR_VAR FloatRegister f18 = {FloatRegisters::f18}; |
|
127 static MOZ_CONSTEXPR_VAR FloatRegister f20 = {FloatRegisters::f20}; |
|
128 static MOZ_CONSTEXPR_VAR FloatRegister f22 = {FloatRegisters::f22}; |
|
129 static MOZ_CONSTEXPR_VAR FloatRegister f24 = {FloatRegisters::f24}; |
|
130 static MOZ_CONSTEXPR_VAR FloatRegister f26 = {FloatRegisters::f26}; |
|
131 static MOZ_CONSTEXPR_VAR FloatRegister f28 = {FloatRegisters::f28}; |
|
132 static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30}; |
|
133 |
|
134 // MIPS CPUs can only load multibyte data that is "naturally" |
|
135 // four-byte-aligned, sp register should be eight-byte-aligned. |
|
136 static const uint32_t StackAlignment = 8; |
|
137 static const uint32_t CodeAlignment = 4; |
|
138 static const bool StackKeptAligned = true; |
|
139 // NativeFrameSize is the size of return adress on stack in AsmJS functions. |
|
140 static const uint32_t NativeFrameSize = sizeof(void*); |
|
141 static const uint32_t AlignmentAtPrologue = 0; |
|
142 static const uint32_t AlignmentMidPrologue = NativeFrameSize; |
|
143 |
|
144 static const Scale ScalePointer = TimesFour; |
|
145 |
|
146 // MIPS instruction types |
|
147 // +---------------------------------------------------------------+ |
|
148 // | 6 | 5 | 5 | 5 | 5 | 6 | |
|
149 // +---------------------------------------------------------------+ |
|
150 // Register type | Opcode | Rs | Rt | Rd | Sa | Function | |
|
151 // +---------------------------------------------------------------+ |
|
152 // | 6 | 5 | 5 | 16 | |
|
153 // +---------------------------------------------------------------+ |
|
154 // Immediate type | Opcode | Rs | Rt | 2's complement constant | |
|
155 // +---------------------------------------------------------------+ |
|
156 // | 6 | 26 | |
|
157 // +---------------------------------------------------------------+ |
|
158 // Jump type | Opcode | jump_target | |
|
159 // +---------------------------------------------------------------+ |
|
160 // 31 bit bit 0 |
|
161 |
|
162 // MIPS instruction encoding constants. |
|
163 static const uint32_t OpcodeShift = 26; |
|
164 static const uint32_t OpcodeBits = 6; |
|
165 static const uint32_t RSShift = 21; |
|
166 static const uint32_t RSBits = 5; |
|
167 static const uint32_t RTShift = 16; |
|
168 static const uint32_t RTBits = 5; |
|
169 static const uint32_t RDShift = 11; |
|
170 static const uint32_t RDBits = 5; |
|
171 static const uint32_t SAShift = 6; |
|
172 static const uint32_t SABits = 5; |
|
173 static const uint32_t FunctionShift = 0; |
|
174 static const uint32_t FunctionBits = 5; |
|
175 static const uint32_t Imm16Shift = 0; |
|
176 static const uint32_t Imm16Bits = 16; |
|
177 static const uint32_t Imm26Shift = 0; |
|
178 static const uint32_t Imm26Bits = 26; |
|
179 static const uint32_t Imm28Shift = 0; |
|
180 static const uint32_t Imm28Bits = 28; |
|
181 static const uint32_t ImmFieldShift = 2; |
|
182 static const uint32_t FccMask = 0x7; |
|
183 static const uint32_t FccShift = 2; |
|
184 |
|
185 |
|
186 // MIPS instruction field bit masks. |
|
187 static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift; |
|
188 static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; |
|
189 static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; |
|
190 static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift; |
|
191 static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift; |
|
192 static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift; |
|
193 static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; |
|
194 static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; |
|
195 static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; |
|
196 static const uint32_t RegMask = Registers::Total - 1; |
|
197 static const uint32_t StackAlignmentMask = StackAlignment - 1; |
|
198 |
|
199 static const int32_t MAX_BREAK_CODE = 1024 - 1; |
|
200 |
|
201 class Instruction; |
|
202 class InstReg; |
|
203 class InstImm; |
|
204 class InstJump; |
|
205 class BranchInstBlock; |
|
206 |
|
207 uint32_t RS(Register r); |
|
208 uint32_t RT(Register r); |
|
209 uint32_t RT(uint32_t regCode); |
|
210 uint32_t RT(FloatRegister r); |
|
211 uint32_t RD(Register r); |
|
212 uint32_t RD(FloatRegister r); |
|
213 uint32_t RD(uint32_t regCode); |
|
214 uint32_t SA(uint32_t value); |
|
215 uint32_t SA(FloatRegister r); |
|
216 |
|
217 Register toRS (Instruction &i); |
|
218 Register toRT (Instruction &i); |
|
219 Register toRD (Instruction &i); |
|
220 Register toR (Instruction &i); |
|
221 |
|
222 // MIPS enums for instruction fields |
|
223 enum Opcode { |
|
224 op_special = 0 << OpcodeShift, |
|
225 op_regimm = 1 << OpcodeShift, |
|
226 |
|
227 op_j = 2 << OpcodeShift, |
|
228 op_jal = 3 << OpcodeShift, |
|
229 op_beq = 4 << OpcodeShift, |
|
230 op_bne = 5 << OpcodeShift, |
|
231 op_blez = 6 << OpcodeShift, |
|
232 op_bgtz = 7 << OpcodeShift, |
|
233 |
|
234 op_addi = 8 << OpcodeShift, |
|
235 op_addiu = 9 << OpcodeShift, |
|
236 op_slti = 10 << OpcodeShift, |
|
237 op_sltiu = 11 << OpcodeShift, |
|
238 op_andi = 12 << OpcodeShift, |
|
239 op_ori = 13 << OpcodeShift, |
|
240 op_xori = 14 << OpcodeShift, |
|
241 op_lui = 15 << OpcodeShift, |
|
242 |
|
243 op_cop1 = 17 << OpcodeShift, |
|
244 op_cop1x = 19 << OpcodeShift, |
|
245 |
|
246 op_beql = 20 << OpcodeShift, |
|
247 op_bnel = 21 << OpcodeShift, |
|
248 op_blezl = 22 << OpcodeShift, |
|
249 op_bgtzl = 23 << OpcodeShift, |
|
250 |
|
251 op_special2 = 28 << OpcodeShift, |
|
252 op_special3 = 31 << OpcodeShift, |
|
253 |
|
254 op_lb = 32 << OpcodeShift, |
|
255 op_lh = 33 << OpcodeShift, |
|
256 op_lwl = 34 << OpcodeShift, |
|
257 op_lw = 35 << OpcodeShift, |
|
258 op_lbu = 36 << OpcodeShift, |
|
259 op_lhu = 37 << OpcodeShift, |
|
260 op_lwr = 38 << OpcodeShift, |
|
261 op_sb = 40 << OpcodeShift, |
|
262 op_sh = 41 << OpcodeShift, |
|
263 op_swl = 42 << OpcodeShift, |
|
264 op_sw = 43 << OpcodeShift, |
|
265 op_swr = 46 << OpcodeShift, |
|
266 |
|
267 op_lwc1 = 49 << OpcodeShift, |
|
268 op_ldc1 = 53 << OpcodeShift, |
|
269 |
|
270 op_swc1 = 57 << OpcodeShift, |
|
271 op_sdc1 = 61 << OpcodeShift |
|
272 }; |
|
273 |
|
274 enum RSField { |
|
275 rs_zero = 0 << RSShift, |
|
276 // cop1 encoding of RS field. |
|
277 rs_mfc1 = 0 << RSShift, |
|
278 rs_one = 1 << RSShift, |
|
279 rs_cfc1 = 2 << RSShift, |
|
280 rs_mfhc1 = 3 << RSShift, |
|
281 rs_mtc1 = 4 << RSShift, |
|
282 rs_ctc1 = 6 << RSShift, |
|
283 rs_mthc1 = 7 << RSShift, |
|
284 rs_bc1 = 8 << RSShift, |
|
285 rs_s = 16 << RSShift, |
|
286 rs_d = 17 << RSShift, |
|
287 rs_w = 20 << RSShift, |
|
288 rs_ps = 22 << RSShift |
|
289 }; |
|
290 |
|
291 enum RTField { |
|
292 rt_zero = 0 << RTShift, |
|
293 // regimm encoding of RT field. |
|
294 rt_bltz = 0 << RTShift, |
|
295 rt_bgez = 1 << RTShift, |
|
296 rt_bltzal = 16 << RTShift, |
|
297 rt_bgezal = 17 << RTShift |
|
298 }; |
|
299 |
|
300 enum FunctionField { |
|
301 // special encoding of function field. |
|
302 ff_sll = 0, |
|
303 ff_movci = 1, |
|
304 ff_srl = 2, |
|
305 ff_sra = 3, |
|
306 ff_sllv = 4, |
|
307 ff_srlv = 6, |
|
308 ff_srav = 7, |
|
309 |
|
310 ff_jr = 8, |
|
311 ff_jalr = 9, |
|
312 ff_movz = 10, |
|
313 ff_movn = 11, |
|
314 ff_break = 13, |
|
315 |
|
316 ff_mfhi = 16, |
|
317 ff_mflo = 18, |
|
318 |
|
319 ff_mult = 24, |
|
320 ff_multu = 25, |
|
321 ff_div = 26, |
|
322 ff_divu = 27, |
|
323 |
|
324 ff_add = 32, |
|
325 ff_addu = 33, |
|
326 ff_sub = 34, |
|
327 ff_subu = 35, |
|
328 ff_and = 36, |
|
329 ff_or = 37, |
|
330 ff_xor = 38, |
|
331 ff_nor = 39, |
|
332 |
|
333 ff_slt = 42, |
|
334 ff_sltu = 43, |
|
335 |
|
336 // special2 encoding of function field. |
|
337 ff_mul = 2, |
|
338 ff_clz = 32, |
|
339 ff_clo = 33, |
|
340 |
|
341 // special3 encoding of function field. |
|
342 ff_ext = 0, |
|
343 ff_ins = 4, |
|
344 |
|
345 // cop1 encoding of function field. |
|
346 ff_add_fmt = 0, |
|
347 ff_sub_fmt = 1, |
|
348 ff_mul_fmt = 2, |
|
349 ff_div_fmt = 3, |
|
350 ff_sqrt_fmt = 4, |
|
351 ff_abs_fmt = 5, |
|
352 ff_mov_fmt = 6, |
|
353 ff_neg_fmt = 7, |
|
354 |
|
355 ff_round_w_fmt = 12, |
|
356 ff_trunc_w_fmt = 13, |
|
357 ff_ceil_w_fmt = 14, |
|
358 ff_floor_w_fmt = 15, |
|
359 |
|
360 ff_cvt_s_fmt = 32, |
|
361 ff_cvt_d_fmt = 33, |
|
362 ff_cvt_w_fmt = 36, |
|
363 |
|
364 ff_c_f_fmt = 48, |
|
365 ff_c_un_fmt = 49, |
|
366 ff_c_eq_fmt = 50, |
|
367 ff_c_ueq_fmt = 51, |
|
368 ff_c_olt_fmt = 52, |
|
369 ff_c_ult_fmt = 53, |
|
370 ff_c_ole_fmt = 54, |
|
371 ff_c_ule_fmt = 55, |
|
372 }; |
|
373 |
|
374 class MacroAssemblerMIPS; |
|
375 class Operand; |
|
376 |
|
377 // A BOffImm16 is a 16 bit immediate that is used for branches. |
|
378 class BOffImm16 |
|
379 { |
|
380 uint32_t data; |
|
381 |
|
382 public: |
|
383 uint32_t encode() { |
|
384 JS_ASSERT(!isInvalid()); |
|
385 return data; |
|
386 } |
|
387 int32_t decode() { |
|
388 JS_ASSERT(!isInvalid()); |
|
389 return (int32_t(data << 18) >> 16) + 4; |
|
390 } |
|
391 |
|
392 explicit BOffImm16(int offset) |
|
393 : data ((offset - 4) >> 2 & Imm16Mask) |
|
394 { |
|
395 JS_ASSERT((offset & 0x3) == 0); |
|
396 JS_ASSERT(isInRange(offset)); |
|
397 } |
|
398 static bool isInRange(int offset) { |
|
399 if ((offset - 4) < (INT16_MIN << 2)) |
|
400 return false; |
|
401 if ((offset - 4) > (INT16_MAX << 2)) |
|
402 return false; |
|
403 return true; |
|
404 } |
|
405 static const uint32_t INVALID = 0x00020000; |
|
406 BOffImm16() |
|
407 : data(INVALID) |
|
408 { } |
|
409 |
|
410 bool isInvalid() { |
|
411 return data == INVALID; |
|
412 } |
|
413 Instruction *getDest(Instruction *src); |
|
414 |
|
415 BOffImm16(InstImm inst); |
|
416 }; |
|
417 |
|
418 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. |
|
419 class JOffImm26 |
|
420 { |
|
421 uint32_t data; |
|
422 |
|
423 public: |
|
424 uint32_t encode() { |
|
425 JS_ASSERT(!isInvalid()); |
|
426 return data; |
|
427 } |
|
428 int32_t decode() { |
|
429 JS_ASSERT(!isInvalid()); |
|
430 return (int32_t(data << 8) >> 6) + 4; |
|
431 } |
|
432 |
|
433 explicit JOffImm26(int offset) |
|
434 : data ((offset - 4) >> 2 & Imm26Mask) |
|
435 { |
|
436 JS_ASSERT((offset & 0x3) == 0); |
|
437 JS_ASSERT(isInRange(offset)); |
|
438 } |
|
439 static bool isInRange(int offset) { |
|
440 if ((offset - 4) < -536870912) |
|
441 return false; |
|
442 if ((offset - 4) > 536870908) |
|
443 return false; |
|
444 return true; |
|
445 } |
|
446 static const uint32_t INVALID = 0x20000000; |
|
447 JOffImm26() |
|
448 : data(INVALID) |
|
449 { } |
|
450 |
|
451 bool isInvalid() { |
|
452 return data == INVALID; |
|
453 } |
|
454 Instruction *getDest(Instruction *src); |
|
455 |
|
456 }; |
|
457 |
|
458 class Imm16 |
|
459 { |
|
460 uint16_t value; |
|
461 |
|
462 public: |
|
463 Imm16(); |
|
464 Imm16(uint32_t imm) |
|
465 : value(imm) |
|
466 { } |
|
467 uint32_t encode() { |
|
468 return value; |
|
469 } |
|
470 int32_t decodeSigned() { |
|
471 return value; |
|
472 } |
|
473 uint32_t decodeUnsigned() { |
|
474 return value; |
|
475 } |
|
476 static bool isInSignedRange(int32_t imm) { |
|
477 return imm >= INT16_MIN && imm <= INT16_MAX; |
|
478 } |
|
479 static bool isInUnsignedRange(uint32_t imm) { |
|
480 return imm <= UINT16_MAX ; |
|
481 } |
|
482 static Imm16 lower (Imm32 imm) { |
|
483 return Imm16(imm.value & 0xffff); |
|
484 } |
|
485 static Imm16 upper (Imm32 imm) { |
|
486 return Imm16((imm.value >> 16) & 0xffff); |
|
487 } |
|
488 }; |
|
489 |
|
490 class Operand |
|
491 { |
|
492 public: |
|
493 enum Tag { |
|
494 REG, |
|
495 FREG, |
|
496 MEM |
|
497 }; |
|
498 |
|
499 private: |
|
500 Tag tag : 3; |
|
501 uint32_t reg : 5; |
|
502 int32_t offset; |
|
503 |
|
504 public: |
|
505 Operand (Register reg_) |
|
506 : tag(REG), reg(reg_.code()) |
|
507 { } |
|
508 |
|
509 Operand (FloatRegister freg) |
|
510 : tag(FREG), reg(freg.code()) |
|
511 { } |
|
512 |
|
513 Operand (Register base, Imm32 off) |
|
514 : tag(MEM), reg(base.code()), offset(off.value) |
|
515 { } |
|
516 |
|
517 Operand (Register base, int32_t off) |
|
518 : tag(MEM), reg(base.code()), offset(off) |
|
519 { } |
|
520 |
|
521 Operand (const Address &addr) |
|
522 : tag(MEM), reg(addr.base.code()), offset(addr.offset) |
|
523 { } |
|
524 |
|
525 Tag getTag() const { |
|
526 return tag; |
|
527 } |
|
528 |
|
529 Register toReg() const { |
|
530 JS_ASSERT(tag == REG); |
|
531 return Register::FromCode(reg); |
|
532 } |
|
533 |
|
534 FloatRegister toFReg() const { |
|
535 JS_ASSERT(tag == FREG); |
|
536 return FloatRegister::FromCode(reg); |
|
537 } |
|
538 |
|
539 void toAddr(Register *r, Imm32 *dest) const { |
|
540 JS_ASSERT(tag == MEM); |
|
541 *r = Register::FromCode(reg); |
|
542 *dest = Imm32(offset); |
|
543 } |
|
544 Address toAddress() const { |
|
545 JS_ASSERT(tag == MEM); |
|
546 return Address(Register::FromCode(reg), offset); |
|
547 } |
|
548 int32_t disp() const { |
|
549 JS_ASSERT(tag == MEM); |
|
550 return offset; |
|
551 } |
|
552 |
|
553 int32_t base() const { |
|
554 JS_ASSERT(tag == MEM); |
|
555 return reg; |
|
556 } |
|
557 Register baseReg() const { |
|
558 JS_ASSERT(tag == MEM); |
|
559 return Register::FromCode(reg); |
|
560 } |
|
561 }; |
|
562 |
|
563 void |
|
564 PatchJump(CodeLocationJump &jump_, CodeLocationLabel label); |
|
565 class Assembler; |
|
566 typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer; |
|
567 |
|
568 class Assembler : public AssemblerShared |
|
569 { |
|
570 public: |
|
571 |
|
572 enum Condition { |
|
573 Equal, |
|
574 NotEqual, |
|
575 Above, |
|
576 AboveOrEqual, |
|
577 Below, |
|
578 BelowOrEqual, |
|
579 GreaterThan, |
|
580 GreaterThanOrEqual, |
|
581 LessThan, |
|
582 LessThanOrEqual, |
|
583 Overflow, |
|
584 Signed, |
|
585 NotSigned, |
|
586 Zero, |
|
587 NonZero, |
|
588 Always, |
|
589 }; |
|
590 |
|
591 enum DoubleCondition { |
|
592 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. |
|
593 DoubleOrdered, |
|
594 DoubleEqual, |
|
595 DoubleNotEqual, |
|
596 DoubleGreaterThan, |
|
597 DoubleGreaterThanOrEqual, |
|
598 DoubleLessThan, |
|
599 DoubleLessThanOrEqual, |
|
600 // If either operand is NaN, these conditions always evaluate to true. |
|
601 DoubleUnordered, |
|
602 DoubleEqualOrUnordered, |
|
603 DoubleNotEqualOrUnordered, |
|
604 DoubleGreaterThanOrUnordered, |
|
605 DoubleGreaterThanOrEqualOrUnordered, |
|
606 DoubleLessThanOrUnordered, |
|
607 DoubleLessThanOrEqualOrUnordered |
|
608 }; |
|
609 |
|
610 enum FPConditionBit { |
|
611 FCC0 = 0, |
|
612 FCC1, |
|
613 FCC2, |
|
614 FCC3, |
|
615 FCC4, |
|
616 FCC5, |
|
617 FCC6, |
|
618 FCC7 |
|
619 }; |
|
620 |
|
621 enum FloatFormat { |
|
622 SingleFloat, |
|
623 DoubleFloat |
|
624 }; |
|
625 |
|
626 enum JumpOrCall { |
|
627 BranchIsJump, |
|
628 BranchIsCall |
|
629 }; |
|
630 |
|
631 enum FloatTestKind { |
|
632 TestForTrue, |
|
633 TestForFalse |
|
634 }; |
|
635 |
|
636 // :( this should be protected, but since CodeGenerator |
|
637 // wants to use it, It needs to go out here :( |
|
638 |
|
639 BufferOffset nextOffset() { |
|
640 return m_buffer.nextOffset(); |
|
641 } |
|
642 |
|
643 protected: |
|
644 Instruction * editSrc (BufferOffset bo) { |
|
645 return m_buffer.getInst(bo); |
|
646 } |
|
647 public: |
|
648 uint32_t actualOffset(uint32_t) const; |
|
649 uint32_t actualIndex(uint32_t) const; |
|
650 static uint8_t *PatchableJumpAddress(JitCode *code, uint32_t index); |
|
651 protected: |
|
652 |
|
653 // structure for fixing up pc-relative loads/jumps when a the machine code |
|
654 // gets moved (executable copy, gc, etc.) |
|
655 struct RelativePatch |
|
656 { |
|
657 // the offset within the code buffer where the value is loaded that |
|
658 // we want to fix-up |
|
659 BufferOffset offset; |
|
660 void *target; |
|
661 Relocation::Kind kind; |
|
662 |
|
663 RelativePatch(BufferOffset offset, void *target, Relocation::Kind kind) |
|
664 : offset(offset), |
|
665 target(target), |
|
666 kind(kind) |
|
667 { } |
|
668 }; |
|
669 |
|
670 js::Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_; |
|
671 js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_; |
|
672 js::Vector<uint32_t, 8, SystemAllocPolicy> longJumps_; |
|
673 |
|
674 CompactBufferWriter jumpRelocations_; |
|
675 CompactBufferWriter dataRelocations_; |
|
676 CompactBufferWriter relocations_; |
|
677 CompactBufferWriter preBarriers_; |
|
678 |
|
679 bool enoughMemory_; |
|
680 |
|
681 MIPSBuffer m_buffer; |
|
682 |
|
683 public: |
|
684 Assembler() |
|
685 : enoughMemory_(true), |
|
686 m_buffer(), |
|
687 isFinished(false) |
|
688 { } |
|
689 |
|
690 static Condition InvertCondition(Condition cond); |
|
691 static DoubleCondition InvertCondition(DoubleCondition cond); |
|
692 |
|
693 // MacroAssemblers hold onto gcthings, so they are traced by the GC. |
|
694 void trace(JSTracer *trc); |
|
695 void writeRelocation(BufferOffset src) { |
|
696 jumpRelocations_.writeUnsigned(src.getOffset()); |
|
697 } |
|
698 |
|
699 // As opposed to x86/x64 version, the data relocation has to be executed |
|
700 // before to recover the pointer, and not after. |
|
701 void writeDataRelocation(const ImmGCPtr &ptr) { |
|
702 if (ptr.value) |
|
703 dataRelocations_.writeUnsigned(nextOffset().getOffset()); |
|
704 } |
|
705 void writePrebarrierOffset(CodeOffsetLabel label) { |
|
706 preBarriers_.writeUnsigned(label.offset()); |
|
707 } |
|
708 |
|
709 public: |
|
710 static uintptr_t getPointer(uint8_t *); |
|
711 |
|
712 bool oom() const; |
|
713 |
|
714 void setPrinter(Sprinter *sp) { |
|
715 } |
|
716 |
|
717 private: |
|
718 bool isFinished; |
|
719 public: |
|
720 void finish(); |
|
721 void executableCopy(void *buffer); |
|
722 void copyJumpRelocationTable(uint8_t *dest); |
|
723 void copyDataRelocationTable(uint8_t *dest); |
|
724 void copyPreBarrierTable(uint8_t *dest); |
|
725 |
|
726 bool addCodeLabel(CodeLabel label); |
|
727 size_t numCodeLabels() const { |
|
728 return codeLabels_.length(); |
|
729 } |
|
730 CodeLabel codeLabel(size_t i) { |
|
731 return codeLabels_[i]; |
|
732 } |
|
733 |
|
734 // Size of the instruction stream, in bytes. |
|
735 size_t size() const; |
|
736 // Size of the jump relocation table, in bytes. |
|
737 size_t jumpRelocationTableBytes() const; |
|
738 size_t dataRelocationTableBytes() const; |
|
739 size_t preBarrierTableBytes() const; |
|
740 |
|
741 // Size of the data table, in bytes. |
|
742 size_t bytesNeeded() const; |
|
743 |
|
744 // Write a blob of binary into the instruction stream *OR* |
|
745 // into a destination address. If dest is nullptr (the default), then the |
|
746 // instruction gets written into the instruction stream. If dest is not null |
|
747 // it is interpreted as a pointer to the location that we want the |
|
748 // instruction to be written. |
|
749 BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr); |
|
750 // A static variant for the cases where we don't want to have an assembler |
|
751 // object at all. Normally, you would use the dummy (nullptr) object. |
|
752 static void writeInstStatic(uint32_t x, uint32_t *dest); |
|
753 |
|
754 public: |
|
755 BufferOffset align(int alignment); |
|
756 BufferOffset as_nop(); |
|
757 |
|
758 // Branch and jump instructions |
|
759 BufferOffset as_bal(BOffImm16 off); |
|
760 |
|
761 InstImm getBranchCode(JumpOrCall jumpOrCall); |
|
762 InstImm getBranchCode(Register s, Register t, Condition c); |
|
763 InstImm getBranchCode(Register s, Condition c); |
|
764 InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc); |
|
765 |
|
766 BufferOffset as_j(JOffImm26 off); |
|
767 BufferOffset as_jal(JOffImm26 off); |
|
768 |
|
769 BufferOffset as_jr(Register rs); |
|
770 BufferOffset as_jalr(Register rs); |
|
771 |
|
772 // Arithmetic instructions |
|
773 BufferOffset as_addu(Register rd, Register rs, Register rt); |
|
774 BufferOffset as_addiu(Register rd, Register rs, int32_t j); |
|
775 BufferOffset as_subu(Register rd, Register rs, Register rt); |
|
776 BufferOffset as_mult(Register rs, Register rt); |
|
777 BufferOffset as_multu(Register rs, Register rt); |
|
778 BufferOffset as_div(Register rs, Register rt); |
|
779 BufferOffset as_divu(Register rs, Register rt); |
|
780 BufferOffset as_mul(Register rd, Register rs, Register rt); |
|
781 |
|
782 // Logical instructions |
|
783 BufferOffset as_and(Register rd, Register rs, Register rt); |
|
784 BufferOffset as_or(Register rd, Register rs, Register rt); |
|
785 BufferOffset as_xor(Register rd, Register rs, Register rt); |
|
786 BufferOffset as_nor(Register rd, Register rs, Register rt); |
|
787 |
|
788 BufferOffset as_andi(Register rd, Register rs, int32_t j); |
|
789 BufferOffset as_ori(Register rd, Register rs, int32_t j); |
|
790 BufferOffset as_xori(Register rd, Register rs, int32_t j); |
|
791 BufferOffset as_lui(Register rd, int32_t j); |
|
792 |
|
793 // Shift instructions |
|
794 // as_sll(zero, zero, x) instructions are reserved as nop |
|
795 BufferOffset as_sll(Register rd, Register rt, uint16_t sa); |
|
796 BufferOffset as_sllv(Register rd, Register rt, Register rs); |
|
797 BufferOffset as_srl(Register rd, Register rt, uint16_t sa); |
|
798 BufferOffset as_srlv(Register rd, Register rt, Register rs); |
|
799 BufferOffset as_sra(Register rd, Register rt, uint16_t sa); |
|
800 BufferOffset as_srav(Register rd, Register rt, Register rs); |
|
801 BufferOffset as_rotr(Register rd, Register rt, uint16_t sa); |
|
802 BufferOffset as_rotrv(Register rd, Register rt, Register rs); |
|
803 |
|
804 // Load and store instructions |
|
805 BufferOffset as_lb(Register rd, Register rs, int16_t off); |
|
806 BufferOffset as_lbu(Register rd, Register rs, int16_t off); |
|
807 BufferOffset as_lh(Register rd, Register rs, int16_t off); |
|
808 BufferOffset as_lhu(Register rd, Register rs, int16_t off); |
|
809 BufferOffset as_lw(Register rd, Register rs, int16_t off); |
|
810 BufferOffset as_lwl(Register rd, Register rs, int16_t off); |
|
811 BufferOffset as_lwr(Register rd, Register rs, int16_t off); |
|
812 BufferOffset as_sb(Register rd, Register rs, int16_t off); |
|
813 BufferOffset as_sh(Register rd, Register rs, int16_t off); |
|
814 BufferOffset as_sw(Register rd, Register rs, int16_t off); |
|
815 BufferOffset as_swl(Register rd, Register rs, int16_t off); |
|
816 BufferOffset as_swr(Register rd, Register rs, int16_t off); |
|
817 |
|
818 // Move from HI/LO register. |
|
819 BufferOffset as_mfhi(Register rd); |
|
820 BufferOffset as_mflo(Register rd); |
|
821 |
|
822 // Set on less than. |
|
823 BufferOffset as_slt(Register rd, Register rs, Register rt); |
|
824 BufferOffset as_sltu(Register rd, Register rs, Register rt); |
|
825 BufferOffset as_slti(Register rd, Register rs, int32_t j); |
|
826 BufferOffset as_sltiu(Register rd, Register rs, uint32_t j); |
|
827 |
|
828 // Conditional move. |
|
829 BufferOffset as_movz(Register rd, Register rs, Register rt); |
|
830 BufferOffset as_movn(Register rd, Register rs, Register rt); |
|
831 BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0); |
|
832 BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0); |
|
833 |
|
834 // Bit twiddling. |
|
835 BufferOffset as_clz(Register rd, Register rs, Register rt = Register::FromCode(0)); |
|
836 BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size); |
|
837 BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size); |
|
838 |
|
839 // FP instructions |
|
840 |
|
841 // Use these two functions only when you are sure address is aligned. |
|
842 // Otherwise, use ma_ld and ma_sd. |
|
843 BufferOffset as_ld(FloatRegister fd, Register base, int32_t off); |
|
844 BufferOffset as_sd(FloatRegister fd, Register base, int32_t off); |
|
845 |
|
846 BufferOffset as_ls(FloatRegister fd, Register base, int32_t off); |
|
847 BufferOffset as_ss(FloatRegister fd, Register base, int32_t off); |
|
848 |
|
849 BufferOffset as_movs(FloatRegister fd, FloatRegister fs); |
|
850 BufferOffset as_movd(FloatRegister fd, FloatRegister fs); |
|
851 |
|
852 BufferOffset as_mtc1(Register rt, FloatRegister fs); |
|
853 BufferOffset as_mfc1(Register rt, FloatRegister fs); |
|
854 |
|
855 protected: |
|
856 // This is used to access the odd regiter form the pair of single |
|
857 // precision registers that make one double register. |
|
858 FloatRegister getOddPair(FloatRegister reg) { |
|
859 JS_ASSERT(reg.code() % 2 == 0); |
|
860 return FloatRegister::FromCode(reg.code() + 1); |
|
861 } |
|
862 |
|
863 public: |
|
864 // FP convert instructions |
|
865 BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); |
|
866 BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); |
|
867 BufferOffset as_roundws(FloatRegister fd, FloatRegister fs); |
|
868 BufferOffset as_truncws(FloatRegister fd, FloatRegister fs); |
|
869 |
|
870 BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs); |
|
871 BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs); |
|
872 BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs); |
|
873 BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs); |
|
874 |
|
875 BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs); |
|
876 BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs); |
|
877 BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs); |
|
878 BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs); |
|
879 BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs); |
|
880 BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs); |
|
881 BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs); |
|
882 BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs); |
|
883 BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs); |
|
884 BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs); |
|
885 |
|
886 // FP arithmetic instructions |
|
887 BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
888 BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
889 BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
890 BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
891 |
|
892 BufferOffset as_abss(FloatRegister fd, FloatRegister fs); |
|
893 BufferOffset as_absd(FloatRegister fd, FloatRegister fs); |
|
894 BufferOffset as_negd(FloatRegister fd, FloatRegister fs); |
|
895 |
|
896 BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
897 BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
898 BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
899 BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
|
900 BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs); |
|
901 BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs); |
|
902 |
|
903 // FP compare instructions |
|
904 BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
905 FPConditionBit fcc = FCC0); |
|
906 BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
907 FPConditionBit fcc = FCC0); |
|
908 BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
909 FPConditionBit fcc = FCC0); |
|
910 BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
911 FPConditionBit fcc = FCC0); |
|
912 BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
913 FPConditionBit fcc = FCC0); |
|
914 BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
915 FPConditionBit fcc = FCC0); |
|
916 BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
917 FPConditionBit fcc = FCC0); |
|
918 BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
|
919 FPConditionBit fcc = FCC0); |
|
920 |
|
921 // label operations |
|
922 void bind(Label *label, BufferOffset boff = BufferOffset()); |
|
923 void bind(RepatchLabel *label); |
|
924 uint32_t currentOffset() { |
|
925 return nextOffset().getOffset(); |
|
926 } |
|
927 void retarget(Label *label, Label *target); |
|
928 void Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address); |
|
929 |
|
930 // See Bind |
|
931 size_t labelOffsetToPatchOffset(size_t offset) { |
|
932 return actualOffset(offset); |
|
933 } |
|
934 |
|
935 void call(Label *label); |
|
936 void call(void *target); |
|
937 |
|
938 void as_break(uint32_t code); |
|
939 |
|
940 public: |
|
941 static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); |
|
942 static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); |
|
943 |
|
944 protected: |
|
945 InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); |
|
946 void bind(InstImm *inst, uint32_t branch, uint32_t target); |
|
947 void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { |
|
948 enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); |
|
949 if (kind == Relocation::JITCODE) |
|
950 writeRelocation(src); |
|
951 } |
|
952 |
|
953 void addLongJump(BufferOffset src) { |
|
954 enoughMemory_ &= longJumps_.append(src.getOffset()); |
|
955 } |
|
956 |
|
957 public: |
|
958 size_t numLongJumps() const { |
|
959 return longJumps_.length(); |
|
960 } |
|
961 uint32_t longJump(size_t i) { |
|
962 return longJumps_[i]; |
|
963 } |
|
964 |
|
965 // Copy the assembly code to the given buffer, and perform any pending |
|
966 // relocations relying on the target address. |
|
967 void executableCopy(uint8_t *buffer); |
|
968 |
|
969 void flushBuffer() { |
|
970 } |
|
971 |
|
972 static uint32_t patchWrite_NearCallSize(); |
|
973 static uint32_t nopSize() { return 4; } |
|
974 |
|
975 static uint32_t extractLuiOriValue(Instruction *inst0, Instruction *inst1); |
|
976 static void updateLuiOriValue(Instruction *inst0, Instruction *inst1, uint32_t value); |
|
977 static void writeLuiOriInstructions(Instruction *inst, Instruction *inst1, |
|
978 Register reg, uint32_t value); |
|
979 |
|
980 static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall); |
|
981 static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, |
|
982 PatchedImmPtr expectedValue); |
|
983 static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, |
|
984 ImmPtr expectedValue); |
|
985 static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm); |
|
986 static uint32_t alignDoubleArg(uint32_t offset) { |
|
987 return (offset + 1U) &~ 1U; |
|
988 } |
|
989 |
|
990 static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr); |
|
991 |
|
992 static void ToggleToJmp(CodeLocationLabel inst_); |
|
993 static void ToggleToCmp(CodeLocationLabel inst_); |
|
994 |
|
995 static void ToggleCall(CodeLocationLabel inst_, bool enabled); |
|
996 |
|
997 static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst); |
|
998 void processCodeLabels(uint8_t *rawCode); |
|
999 |
|
1000 bool bailed() { |
|
1001 return m_buffer.bail(); |
|
1002 } |
|
1003 }; // Assembler |
|
1004 |
|
1005 // An Instruction is a structure for both encoding and decoding any and all |
|
1006 // MIPS instructions. |
|
1007 class Instruction |
|
1008 { |
|
1009 protected: |
|
1010 // sll zero, zero, 0 |
|
1011 static const uint32_t NopInst = 0x00000000; |
|
1012 |
|
1013 uint32_t data; |
|
1014 |
|
1015 // Standard constructor |
|
1016 Instruction (uint32_t data_) : data(data_) { } |
|
1017 |
|
1018 // You should never create an instruction directly. You should create a |
|
1019 // more specific instruction which will eventually call one of these |
|
1020 // constructors for you. |
|
1021 public: |
|
1022 uint32_t encode() const { |
|
1023 return data; |
|
1024 } |
|
1025 |
|
1026 void makeNop() { |
|
1027 data = NopInst; |
|
1028 } |
|
1029 |
|
1030 void setData(uint32_t data) { |
|
1031 this->data = data; |
|
1032 } |
|
1033 |
|
1034 const Instruction & operator=(const Instruction &src) { |
|
1035 data = src.data; |
|
1036 return *this; |
|
1037 } |
|
1038 |
|
1039 // Extract the one particular bit. |
|
1040 uint32_t extractBit(uint32_t bit) { |
|
1041 return (encode() >> bit) & 1; |
|
1042 } |
|
1043 // Extract a bit field out of the instruction |
|
1044 uint32_t extractBitField(uint32_t hi, uint32_t lo) { |
|
1045 return (encode() >> lo) & ((2 << (hi - lo)) - 1); |
|
1046 } |
|
1047 // Since all MIPS instructions have opcode, the opcode |
|
1048 // extractor resides in the base class. |
|
1049 uint32_t extractOpcode() { |
|
1050 return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); |
|
1051 } |
|
1052 // Return the fields at their original place in the instruction encoding. |
|
1053 Opcode OpcodeFieldRaw() const { |
|
1054 return static_cast<Opcode>(encode() & OpcodeMask); |
|
1055 } |
|
1056 |
|
1057 // Get the next instruction in the instruction stream. |
|
1058 // This does neat things like ignoreconstant pools and their guards. |
|
1059 Instruction *next(); |
|
1060 |
|
1061 // Sometimes, an api wants a uint32_t (or a pointer to it) rather than |
|
1062 // an instruction. raw() just coerces this into a pointer to a uint32_t |
|
1063 const uint32_t *raw() const { return &data; } |
|
1064 uint32_t size() const { return 4; } |
|
1065 }; // Instruction |
|
1066 |
|
1067 // make sure that it is the right size |
|
1068 static_assert(sizeof(Instruction) == 4, "Size of Instruction class has to be 4 bytes."); |
|
1069 |
|
1070 class InstNOP : public Instruction |
|
1071 { |
|
1072 public: |
|
1073 InstNOP() |
|
1074 : Instruction(NopInst) |
|
1075 { } |
|
1076 |
|
1077 }; |
|
1078 |
|
1079 // Class for register type instructions. |
|
1080 class InstReg : public Instruction |
|
1081 { |
|
1082 public: |
|
1083 InstReg(Opcode op, Register rd, FunctionField ff) |
|
1084 : Instruction(op | RD(rd) | ff) |
|
1085 { } |
|
1086 InstReg(Opcode op, Register rs, Register rt, FunctionField ff) |
|
1087 : Instruction(op | RS(rs) | RT(rt) | ff) |
|
1088 { } |
|
1089 InstReg(Opcode op, Register rs, Register rt, Register rd, FunctionField ff) |
|
1090 : Instruction(op | RS(rs) | RT(rt) | RD(rd) | ff) |
|
1091 { } |
|
1092 InstReg(Opcode op, Register rs, Register rt, Register rd, uint32_t sa, FunctionField ff) |
|
1093 : Instruction(op | RS(rs) | RT(rt) | RD(rd) | SA(sa) | ff) |
|
1094 { } |
|
1095 InstReg(Opcode op, RSField rs, Register rt, Register rd, uint32_t sa, FunctionField ff) |
|
1096 : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) |
|
1097 { } |
|
1098 InstReg(Opcode op, Register rs, RTField rt, Register rd, uint32_t sa, FunctionField ff) |
|
1099 : Instruction(op | RS(rs) | rt | RD(rd) | SA(sa) | ff) |
|
1100 { } |
|
1101 InstReg(Opcode op, Register rs, uint32_t cc, Register rd, uint32_t sa, FunctionField ff) |
|
1102 : Instruction(op | RS(rs) | cc | RD(rd) | SA(sa) | ff) |
|
1103 { } |
|
1104 InstReg(Opcode op, uint32_t code, FunctionField ff) |
|
1105 : Instruction(op | code | ff) |
|
1106 { } |
|
1107 // for float point |
|
1108 InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd) |
|
1109 : Instruction(op | rs | RT(rt) | RD(rd)) |
|
1110 { } |
|
1111 InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd, uint32_t sa, FunctionField ff) |
|
1112 : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) |
|
1113 { } |
|
1114 InstReg(Opcode op, RSField rs, Register rt, FloatRegister fs, FloatRegister fd, FunctionField ff) |
|
1115 : Instruction(op | rs | RT(rt) | RD(fs) | SA(fd) | ff) |
|
1116 { } |
|
1117 InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fs, FloatRegister fd, FunctionField ff) |
|
1118 : Instruction(op | rs | RT(ft) | RD(fs) | SA(fd) | ff) |
|
1119 { } |
|
1120 InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fd, uint32_t sa, FunctionField ff) |
|
1121 : Instruction(op | rs | RT(ft) | RD(fd) | SA(sa) | ff) |
|
1122 { } |
|
1123 |
|
1124 uint32_t extractRS () { |
|
1125 return extractBitField(RSShift + RSBits - 1, RSShift); |
|
1126 } |
|
1127 uint32_t extractRT () { |
|
1128 return extractBitField(RTShift + RTBits - 1, RTShift); |
|
1129 } |
|
1130 uint32_t extractRD () { |
|
1131 return extractBitField(RDShift + RDBits - 1, RDShift); |
|
1132 } |
|
1133 uint32_t extractSA () { |
|
1134 return extractBitField(SAShift + SABits - 1, SAShift); |
|
1135 } |
|
1136 uint32_t extractFunctionField () { |
|
1137 return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift); |
|
1138 } |
|
1139 }; |
|
1140 |
|
1141 // Class for branch, load and store instructions with immediate offset. |
|
1142 class InstImm : public Instruction |
|
1143 { |
|
1144 public: |
|
1145 void extractImm16(BOffImm16 *dest); |
|
1146 |
|
1147 InstImm(Opcode op, Register rs, Register rt, BOffImm16 off) |
|
1148 : Instruction(op | RS(rs) | RT(rt) | off.encode()) |
|
1149 { } |
|
1150 InstImm(Opcode op, Register rs, RTField rt, BOffImm16 off) |
|
1151 : Instruction(op | RS(rs) | rt | off.encode()) |
|
1152 { } |
|
1153 InstImm(Opcode op, RSField rs, uint32_t cc, BOffImm16 off) |
|
1154 : Instruction(op | rs | cc | off.encode()) |
|
1155 { } |
|
1156 InstImm(Opcode op, Register rs, Register rt, Imm16 off) |
|
1157 : Instruction(op | RS(rs) | RT(rt) | off.encode()) |
|
1158 { } |
|
1159 InstImm(uint32_t raw) |
|
1160 : Instruction(raw) |
|
1161 { } |
|
1162 // For floating-point loads and stores. |
|
1163 InstImm(Opcode op, Register rs, FloatRegister rt, Imm16 off) |
|
1164 : Instruction(op | RS(rs) | RT(rt) | off.encode()) |
|
1165 { } |
|
1166 |
|
1167 uint32_t extractOpcode() { |
|
1168 return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); |
|
1169 } |
|
1170 void setOpcode(Opcode op) { |
|
1171 data = (data & ~OpcodeMask) | op; |
|
1172 } |
|
1173 uint32_t extractRS() { |
|
1174 return extractBitField(RSShift + RSBits - 1, RSShift); |
|
1175 } |
|
1176 uint32_t extractRT() { |
|
1177 return extractBitField(RTShift + RTBits - 1, RTShift); |
|
1178 } |
|
1179 void setRT(RTField rt) { |
|
1180 data = (data & ~RTMask) | rt; |
|
1181 } |
|
1182 uint32_t extractImm16Value() { |
|
1183 return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); |
|
1184 } |
|
1185 void setBOffImm16(BOffImm16 off) { |
|
1186 // Reset immediate field and replace it |
|
1187 data = (data & ~Imm16Mask) | off.encode(); |
|
1188 } |
|
1189 void setImm16(Imm16 off) { |
|
1190 // Reset immediate field and replace it |
|
1191 data = (data & ~Imm16Mask) | off.encode(); |
|
1192 } |
|
1193 }; |
|
1194 |
|
1195 // Class for Jump type instructions. |
|
1196 class InstJump : public Instruction |
|
1197 { |
|
1198 public: |
|
1199 InstJump(Opcode op, JOffImm26 off) |
|
1200 : Instruction(op | off.encode()) |
|
1201 { } |
|
1202 |
|
1203 uint32_t extractImm26Value() { |
|
1204 return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift); |
|
1205 } |
|
1206 }; |
|
1207 |
|
1208 static const uint32_t NumIntArgRegs = 4; |
|
1209 |
|
1210 static inline bool |
|
1211 GetIntArgReg(uint32_t usedArgSlots, Register *out) |
|
1212 { |
|
1213 if (usedArgSlots < NumIntArgRegs) { |
|
1214 *out = Register::FromCode(a0.code() + usedArgSlots); |
|
1215 return true; |
|
1216 } |
|
1217 return false; |
|
1218 } |
|
1219 |
|
1220 // Get a register in which we plan to put a quantity that will be used as an |
|
1221 // integer argument. This differs from GetIntArgReg in that if we have no more |
|
1222 // actual argument registers to use we will fall back on using whatever |
|
1223 // CallTempReg* don't overlap the argument registers, and only fail once those |
|
1224 // run out too. |
|
1225 static inline bool |
|
1226 GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out) |
|
1227 { |
|
1228 // NOTE: We can't properly determine which regs are used if there are |
|
1229 // float arguments. If this is needed, we will have to guess. |
|
1230 JS_ASSERT(usedFloatArgs == 0); |
|
1231 |
|
1232 if (GetIntArgReg(usedIntArgs, out)) |
|
1233 return true; |
|
1234 // Unfortunately, we have to assume things about the point at which |
|
1235 // GetIntArgReg returns false, because we need to know how many registers it |
|
1236 // can allocate. |
|
1237 usedIntArgs -= NumIntArgRegs; |
|
1238 if (usedIntArgs >= NumCallTempNonArgRegs) |
|
1239 return false; |
|
1240 *out = CallTempNonArgRegs[usedIntArgs]; |
|
1241 return true; |
|
1242 } |
|
1243 |
|
1244 static inline uint32_t |
|
1245 GetArgStackDisp(uint32_t usedArgSlots) |
|
1246 { |
|
1247 JS_ASSERT(usedArgSlots >= NumIntArgRegs); |
|
1248 // Even register arguments have place reserved on stack. |
|
1249 return usedArgSlots * sizeof(intptr_t); |
|
1250 } |
|
1251 |
|
1252 } // namespace jit |
|
1253 } // namespace js |
|
1254 |
|
1255 #endif /* jit_mips_Assembler_mips_h */ |