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 #include "jit/mips32/MoveEmitter-mips32.h"
8 
9 #include "jit/MacroAssembler-inl.h"
10 
11 using namespace js;
12 using namespace js::jit;
13 
14 void
15 MoveEmitterMIPS::breakCycle(const MoveOperand& from, const MoveOperand& to,
16                             MoveOp::Type type, uint32_t slotId)
17 {
18     // There is some pattern:
19     //   (A -> B)
20     //   (B -> A)
21     //
22     // This case handles (A -> B), which we reach first. We save B, then allow
23     // the original move to continue.
24     switch (type) {
25       case MoveOp::FLOAT32:
26         if (to.isMemory()) {
27             FloatRegister temp = ScratchFloat32Reg;
28             masm.loadFloat32(getAdjustedAddress(to), temp);
29             // Since it is uncertain if the load will be aligned or not
30             // just fill both of them with the same value.
31             masm.storeFloat32(temp, cycleSlot(slotId, 0));
32             masm.storeFloat32(temp, cycleSlot(slotId, 4));
33         } else {
34             // Just always store the largest possible size.
35             masm.storeDouble(to.floatReg().doubleOverlay(), cycleSlot(slotId, 0));
36         }
37         break;
38       case MoveOp::DOUBLE:
39         if (to.isMemory()) {
40             FloatRegister temp = ScratchDoubleReg;
41             masm.loadDouble(getAdjustedAddress(to), temp);
42             masm.storeDouble(temp, cycleSlot(slotId, 0));
43         } else {
44             masm.storeDouble(to.floatReg(), cycleSlot(slotId, 0));
45         }
compatible_ftypes(ftenum_t a,ftenum_t b)46         break;
47       case MoveOp::INT32:
48         MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
49       case MoveOp::GENERAL:
50         if (to.isMemory()) {
51             Register temp = tempReg();
52             masm.loadPtr(getAdjustedAddress(to), temp);
53             masm.storePtr(temp, cycleSlot(0, 0));
54         } else {
55             // Second scratch register should not be moved by MoveEmitter.
56             MOZ_ASSERT(to.reg() != spilledReg_);
57             masm.storePtr(to.reg(), cycleSlot(0, 0));
58         }
59         break;
60       default:
61         MOZ_CRASH("Unexpected move type");
62     }
63 }
64 
65 void
66 MoveEmitterMIPS::completeCycle(const MoveOperand& from, const MoveOperand& to,
67                                MoveOp::Type type, uint32_t slotId)
68 {
69     // There is some pattern:
70     //   (A -> B)
71     //   (B -> A)
72     //
73     // This case handles (B -> A), which we reach last. We emit a move from the
74     // saved value of B, to A.
75     switch (type) {
76       case MoveOp::FLOAT32:
77         if (to.isMemory()) {
78             FloatRegister temp = ScratchFloat32Reg;
79             masm.loadFloat32(cycleSlot(slotId, 0), temp);
80             masm.storeFloat32(temp, getAdjustedAddress(to));
81         } else {
82             uint32_t offset = 0;
83             if (from.floatReg().numAlignedAliased() == 1)
84                 offset = sizeof(float);
85             masm.loadFloat32(cycleSlot(slotId, offset), to.floatReg());
86         }
87         break;
88       case MoveOp::DOUBLE:
89         if (to.isMemory()) {
90             FloatRegister temp = ScratchDoubleReg;
91             masm.loadDouble(cycleSlot(slotId, 0), temp);
92             masm.storeDouble(temp, getAdjustedAddress(to));
93         } else {
94             masm.loadDouble(cycleSlot(slotId, 0), to.floatReg());
95         }
96         break;
97       case MoveOp::INT32:
98         MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
99       case MoveOp::GENERAL:
100         MOZ_ASSERT(slotId == 0);
101         if (to.isMemory()) {
102             Register temp = tempReg();
103             masm.loadPtr(cycleSlot(0, 0), temp);
104             masm.storePtr(temp, getAdjustedAddress(to));
105         } else {
106             // Second scratch register should not be moved by MoveEmitter.
107             MOZ_ASSERT(to.reg() != spilledReg_);
108             masm.loadPtr(cycleSlot(0, 0), to.reg());
109         }
110         break;
111       default:
112         MOZ_CRASH("Unexpected move type");
113     }
114 }
115 
116 void
117 MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
118 {
119     // Ensure that we can use ScratchDoubleReg in memory move.
120     MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchDoubleReg);
121     MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchDoubleReg);
122 
123     if (from.isFloatReg()) {
124         if (to.isFloatReg()) {
125             masm.moveDouble(from.floatReg(), to.floatReg());
126         } else if (to.isGeneralRegPair()) {
127             // Used for passing double parameter in a2,a3 register pair.
128             // Two moves are added for one double parameter by
129             // MacroAssembler::passABIArg
130             MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3,
131                        "Invalid emitDoubleMove arguments.");
132             masm.moveFromDoubleLo(from.floatReg(), a2);
133             masm.moveFromDoubleHi(from.floatReg(), a3);
134         } else {
135             MOZ_ASSERT(to.isMemory());
136             masm.storeDouble(from.floatReg(), getAdjustedAddress(to));
137         }
dfilter_fvalue_from_unparsed(dfwork_t * dfw,ftenum_t ftype,const char * s,gboolean allow_partial_value)138     } else if (to.isFloatReg()) {
139         MOZ_ASSERT(from.isMemory());
140         masm.loadDouble(getAdjustedAddress(from), to.floatReg());
141     } else if (to.isGeneralRegPair()) {
142         // Used for passing double parameter in a2,a3 register pair.
143         // Two moves are added for one double parameter by
144         // MacroAssembler::passABIArg
145         MOZ_ASSERT(from.isMemory());
146         MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3,
147                    "Invalid emitDoubleMove arguments.");
148         masm.loadPtr(getAdjustedAddress(from), a2);
dfilter_fvalue_from_string(dfwork_t * dfw,ftenum_t ftype,const char * s)149         masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3);
150     } else {
151         MOZ_ASSERT(from.isMemory());
152         MOZ_ASSERT(to.isMemory());
153         masm.loadDouble(getAdjustedAddress(from), ScratchDoubleReg);
154         masm.storeDouble(ScratchDoubleReg, getAdjustedAddress(to));
155     }
156 }
mk_uint32_fvalue(guint32 val)157