1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 
breakCycle(const MoveOperand & from,const MoveOperand & to,MoveOp::Type type,uint32_t slotId)14 void MoveEmitterMIPS::breakCycle(const MoveOperand& from, const MoveOperand& to,
15                                  MoveOp::Type type, uint32_t slotId) {
16   // There is some pattern:
17   //   (A -> B)
18   //   (B -> A)
19   //
20   // This case handles (A -> B), which we reach first. We save B, then allow
21   // the original move to continue.
22   switch (type) {
23     case MoveOp::FLOAT32:
24       if (to.isMemory()) {
25         FloatRegister temp = ScratchFloat32Reg;
26         masm.loadFloat32(getAdjustedAddress(to), temp);
27         // Since it is uncertain if the load will be aligned or not
28         // just fill both of them with the same value.
29         masm.storeFloat32(temp, cycleSlot(slotId, 0));
30         masm.storeFloat32(temp, cycleSlot(slotId, 4));
31       } else {
32         // Just always store the largest possible size.
33         masm.storeDouble(to.floatReg().doubleOverlay(), cycleSlot(slotId, 0));
34       }
35       break;
36     case MoveOp::DOUBLE:
37       if (to.isMemory()) {
38         FloatRegister temp = ScratchDoubleReg;
39         masm.loadDouble(getAdjustedAddress(to), temp);
40         masm.storeDouble(temp, cycleSlot(slotId, 0));
41       } else {
42         masm.storeDouble(to.floatReg(), cycleSlot(slotId, 0));
43       }
44       break;
45     case MoveOp::INT32:
46       MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
47       [[fallthrough]];
48     case MoveOp::GENERAL:
49       if (to.isMemory()) {
50         Register temp = tempReg();
51         masm.loadPtr(getAdjustedAddress(to), temp);
52         masm.storePtr(temp, cycleSlot(0, 0));
53       } else {
54         // Second scratch register should not be moved by MoveEmitter.
55         MOZ_ASSERT(to.reg() != spilledReg_);
56         masm.storePtr(to.reg(), cycleSlot(0, 0));
57       }
58       break;
59     default:
60       MOZ_CRASH("Unexpected move type");
61   }
62 }
63 
completeCycle(const MoveOperand & from,const MoveOperand & to,MoveOp::Type type,uint32_t slotId)64 void MoveEmitterMIPS::completeCycle(const MoveOperand& from,
65                                     const MoveOperand& to, MoveOp::Type type,
66                                     uint32_t slotId) {
67   // There is some pattern:
68   //   (A -> B)
69   //   (B -> A)
70   //
71   // This case handles (B -> A), which we reach last. We emit a move from the
72   // saved value of B, to A.
73   switch (type) {
74     case MoveOp::FLOAT32:
75       if (to.isMemory()) {
76         FloatRegister temp = ScratchFloat32Reg;
77         masm.loadFloat32(cycleSlot(slotId, 0), temp);
78         masm.storeFloat32(temp, getAdjustedAddress(to));
79       } else {
80         uint32_t offset = 0;
81         if (from.floatReg().numAlignedAliased() == 1) {
82           offset = sizeof(float);
83         }
84         masm.loadFloat32(cycleSlot(slotId, offset), to.floatReg());
85       }
86       break;
87     case MoveOp::DOUBLE:
88       if (to.isMemory()) {
89         FloatRegister temp = ScratchDoubleReg;
90         masm.loadDouble(cycleSlot(slotId, 0), temp);
91         masm.storeDouble(temp, getAdjustedAddress(to));
92       } else {
93         masm.loadDouble(cycleSlot(slotId, 0), to.floatReg());
94       }
95       break;
96     case MoveOp::INT32:
97       MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
98       [[fallthrough]];
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 
emitDoubleMove(const MoveOperand & from,const MoveOperand & to)116 void MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from,
117                                      const MoveOperand& to) {
118   if (from.isFloatReg()) {
119     if (to.isFloatReg()) {
120       masm.moveDouble(from.floatReg(), to.floatReg());
121     } else if (to.isGeneralRegPair()) {
122       // Used for passing double parameter in a2,a3 register pair.
123       // Two moves are added for one double parameter by
124       // MacroAssembler::passABIArg
125       MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3,
126                  "Invalid emitDoubleMove arguments.");
127       masm.moveFromDoubleLo(from.floatReg(), a2);
128       masm.moveFromDoubleHi(from.floatReg(), a3);
129     } else {
130       MOZ_ASSERT(to.isMemory());
131       masm.storeDouble(from.floatReg(), getAdjustedAddress(to));
132     }
133   } else if (to.isFloatReg()) {
134     MOZ_ASSERT(from.isMemory());
135     masm.loadDouble(getAdjustedAddress(from), to.floatReg());
136   } else if (to.isGeneralRegPair()) {
137     // Used for passing double parameter in a2,a3 register pair.
138     // Two moves are added for one double parameter by
139     // MacroAssembler::passABIArg
140     MOZ_ASSERT(from.isMemory());
141     MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3,
142                "Invalid emitDoubleMove arguments.");
143     masm.loadPtr(getAdjustedAddress(from), a2);
144     masm.loadPtr(
145         Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3);
146   } else {
147     MOZ_ASSERT(from.isMemory());
148     MOZ_ASSERT(to.isMemory());
149     masm.loadDouble(getAdjustedAddress(from), ScratchDoubleReg);
150     masm.storeDouble(ScratchDoubleReg, getAdjustedAddress(to));
151   }
152 }
153