blob: f1a656df33c128c521ec55f1ecee0c36c9fcd181 [file] [log] [blame]
Jaydeep Patil135f5db2016-08-29 05:14:05 -07001//===- subzero/src/IceAssemblerMIPS32.cpp - MIPS32 Assembler --------------===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief Implements the Assembler class for MIPS32.
12///
13//===----------------------------------------------------------------------===//
14
15#include "IceAssemblerMIPS32.h"
16#include "IceCfgNode.h"
17#include "IceRegistersMIPS32.h"
18#include "IceUtils.h"
19
20namespace {
21
22using namespace Ice;
23using namespace Ice::MIPS32;
24
25// Offset modifier to current PC for next instruction.
26static constexpr IOffsetT kPCReadOffset = 4;
27
28// Mask to pull out PC offset from branch instruction.
29static constexpr int kBranchOffsetBits = 16;
30static constexpr IOffsetT kBranchOffsetMask = 0x0000ffff;
31
32} // end of anonymous namespace
33
34namespace Ice {
35namespace MIPS32 {
36
37void AssemblerMIPS32::emitTextInst(const std::string &Text, SizeT InstSize) {
38 AssemblerFixup *F = createTextFixup(Text, InstSize);
39 emitFixup(F);
40 for (SizeT I = 0; I < InstSize; ++I) {
41 AssemblerBuffer::EnsureCapacity ensured(&Buffer);
42 Buffer.emit<char>(0);
43 }
44}
45
46namespace {
47
48// TEQ $0, $0 - Trap if equal
49static constexpr uint8_t TrapBytesRaw[] = {0x00, 0x00, 0x00, 0x34};
50
51const auto TrapBytes =
52 llvm::ArrayRef<uint8_t>(TrapBytesRaw, llvm::array_lengthof(TrapBytesRaw));
53
54} // end of anonymous namespace
55
56llvm::ArrayRef<uint8_t> AssemblerMIPS32::getNonExecBundlePadding() const {
57 return TrapBytes;
58}
59
60void AssemblerMIPS32::trap() {
61 AssemblerBuffer::EnsureCapacity ensured(&Buffer);
62 for (const uint8_t &Byte : reverse_range(TrapBytes))
63 Buffer.emit<uint8_t>(Byte);
64}
65
66void AssemblerMIPS32::nop() { emitInst(0); }
67
68void AssemblerMIPS32::padWithNop(intptr_t Padding) {
69 constexpr intptr_t InstWidth = sizeof(IValueT);
70 assert(Padding % InstWidth == 0 &&
71 "Padding not multiple of instruction size");
72 for (intptr_t i = 0; i < Padding; i += InstWidth)
73 nop();
74}
75
76Label *AssemblerMIPS32::getOrCreateLabel(SizeT Number, LabelVector &Labels) {
77 Label *L = nullptr;
78 if (Number == Labels.size()) {
79 L = new (this->allocate<Label>()) Label();
80 Labels.push_back(L);
81 return L;
82 }
83 if (Number > Labels.size()) {
84 Labels.resize(Number + 1);
85 }
86 L = Labels[Number];
87 if (L == nullptr) {
88 L = new (this->allocate<Label>()) Label();
89 Labels[Number] = L;
90 }
91 return L;
92}
93
94void AssemblerMIPS32::bindCfgNodeLabel(const CfgNode *Node) {
95 if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) {
96 constexpr SizeT InstSize = 0;
97 emitTextInst(Node->getAsmName() + ":", InstSize);
98 }
99 SizeT NodeNumber = Node->getIndex();
100 assert(!getPreliminary());
101 Label *L = getOrCreateCfgNodeLabel(NodeNumber);
102 this->bind(L);
103}
104
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700105namespace {
106
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700107// Checks that Offset can fit in imm16 constant of branch instruction.
108void assertCanEncodeBranchOffset(IOffsetT Offset) {
109 (void)Offset;
110 (void)kBranchOffsetBits;
111 assert(Utils::IsAligned(Offset, 4));
112 assert(Utils::IsInt(kBranchOffsetBits, Offset >> 2));
113}
114
115IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) {
116 Offset -= kPCReadOffset;
117 assertCanEncodeBranchOffset(Offset);
118 Offset >>= 2;
119 Offset &= kBranchOffsetMask;
120 return (Inst & ~kBranchOffsetMask) | Offset;
121}
122
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700123enum RegSetWanted { WantGPRegs, WantFPRegs };
124
125IValueT getEncodedGPRegNum(const Variable *Var) {
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700126 assert(Var->hasReg() && isScalarIntegerType(Var->getType()));
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700127 const auto Reg = Var->getRegNum();
128 return RegMIPS32::getEncodedGPR(Reg);
129}
130
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700131IValueT getEncodedFPRegNum(const Variable *Var) {
132 assert(Var->hasReg() && isScalarFloatingType(Var->getType()));
133 const auto Reg = Var->getRegNum();
134 IValueT RegEncoding;
135 if (RegMIPS32::isFPRReg(Reg)) {
136 RegEncoding = RegMIPS32::getEncodedFPR(Reg);
137 } else {
138 RegEncoding = RegMIPS32::getEncodedFPR64(Reg);
139 }
140 return RegEncoding;
141}
142
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700143bool encodeOperand(const Operand *Opnd, IValueT &Value,
144 RegSetWanted WantedRegSet) {
145 Value = 0;
146 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
147 if (Var->hasReg()) {
148 switch (WantedRegSet) {
149 case WantGPRegs:
150 Value = getEncodedGPRegNum(Var);
151 break;
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700152 case WantFPRegs:
153 Value = getEncodedFPRegNum(Var);
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700154 break;
155 }
156 return true;
157 }
158 return false;
159 }
160 return false;
161}
162
163IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
164 const char *RegName, const char *InstName) {
165 IValueT Reg = 0;
166 if (encodeOperand(OpReg, Reg, WantedRegSet) != true)
167 llvm::report_fatal_error(std::string(InstName) + ": Can't find register " +
168 RegName);
169 return Reg;
170}
171
172IValueT encodeGPRegister(const Operand *OpReg, const char *RegName,
173 const char *InstName) {
174 return encodeRegister(OpReg, WantGPRegs, RegName, InstName);
175}
176
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700177IValueT encodeFPRegister(const Operand *OpReg, const char *RegName,
178 const char *InstName) {
179 return encodeRegister(OpReg, WantFPRegs, RegName, InstName);
180}
181
182} // end of anonymous namespace
183
184IOffsetT AssemblerMIPS32::decodeBranchOffset(IValueT Inst) {
185 int16_t imm = (Inst & kBranchOffsetMask);
186 IOffsetT Offset = imm;
187 Offset = Offset << 2;
188 return (Offset + kPCReadOffset);
189}
190
191void AssemblerMIPS32::bind(Label *L) {
192 IOffsetT BoundPc = Buffer.size();
193 assert(!L->isBound()); // Labels can only be bound once.
194 while (L->isLinked()) {
195 IOffsetT Position = L->getLinkPosition();
196 IOffsetT Dest = BoundPc - Position;
197 IValueT Inst = Buffer.load<IValueT>(Position);
198 Buffer.store<IValueT>(Position, encodeBranchOffset(Dest, Inst));
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -0800199 IOffsetT NextBrPc = decodeBranchOffset(Inst);
200 if (NextBrPc != 0)
201 NextBrPc = Position - NextBrPc;
202 L->setPosition(NextBrPc);
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700203 }
204 L->bindTo(BoundPc);
205}
206
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700207void AssemblerMIPS32::emitRsRt(IValueT Opcode, const Operand *OpRs,
208 const Operand *OpRt, const char *InsnName) {
209 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
210 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
211
212 Opcode |= Rs << 21;
213 Opcode |= Rt << 16;
214
215 emitInst(Opcode);
216}
217
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700218void AssemblerMIPS32::emitRtRsImm16(IValueT Opcode, const Operand *OpRt,
219 const Operand *OpRs, const uint32_t Imm,
220 const char *InsnName) {
221 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
222 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
223
224 Opcode |= Rs << 21;
225 Opcode |= Rt << 16;
226 Opcode |= Imm & 0xffff;
227
228 emitInst(Opcode);
229}
230
Jaydeep Patil130aca72016-10-28 05:30:54 -0700231void AssemblerMIPS32::emitRtRsImm16Rel(IValueT Opcode, const Operand *OpRt,
232 const Operand *OpRs,
233 const Operand *OpImm,
234 const RelocOp Reloc,
235 const char *InsnName) {
236 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
237 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
238 uint32_t Imm16 = 0;
239
240 if (const auto *OpRel = llvm::dyn_cast<ConstantRelocatable>(OpImm)) {
241 emitFixup(createMIPS32Fixup(Reloc, OpRel));
242 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(OpImm)) {
243 Imm16 = C32->getValue();
244 } else {
245 llvm::report_fatal_error(std::string(InsnName) + ": Invalid 3rd operand");
246 }
247
248 Opcode |= Rs << 21;
249 Opcode |= Rt << 16;
250 Opcode |= Imm16 & 0xffff;
251
252 emitInst(Opcode);
253}
254
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700255void AssemblerMIPS32::emitFtRsImm16(IValueT Opcode, const Operand *OpFt,
256 const Operand *OpRs, const uint32_t Imm,
257 const char *InsnName) {
258 const IValueT Ft = encodeFPRegister(OpFt, "Ft", InsnName);
259 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
260
261 Opcode |= Rs << 21;
262 Opcode |= Ft << 16;
263 Opcode |= Imm & 0xffff;
264
265 emitInst(Opcode);
266}
267
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700268void AssemblerMIPS32::emitRdRtSa(IValueT Opcode, const Operand *OpRd,
269 const Operand *OpRt, const uint32_t Sa,
270 const char *InsnName) {
271 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName);
272 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
273
274 Opcode |= Rt << 16;
275 Opcode |= Rd << 11;
276 Opcode |= (Sa & 0x1f) << 6;
277
278 emitInst(Opcode);
279}
280
281void AssemblerMIPS32::emitRdRsRt(IValueT Opcode, const Operand *OpRd,
282 const Operand *OpRs, const Operand *OpRt,
283 const char *InsnName) {
284 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName);
285 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
286 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
287
288 Opcode |= Rs << 21;
289 Opcode |= Rt << 16;
290 Opcode |= Rd << 11;
291
292 emitInst(Opcode);
293}
294
Srdjan Obucina8d16c1d2016-09-20 08:44:44 -0700295void AssemblerMIPS32::emitCOP1Fcmp(IValueT Opcode, FPInstDataFormat Format,
296 const Operand *OpFs, const Operand *OpFt,
297 IValueT CC, const char *InsnName) {
298 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName);
299 const IValueT Ft = encodeFPRegister(OpFt, "Ft", InsnName);
300
301 Opcode |= CC << 8;
302 Opcode |= Fs << 11;
303 Opcode |= Ft << 16;
304 Opcode |= Format << 21;
305
306 emitInst(Opcode);
307}
308
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700309void AssemblerMIPS32::emitCOP1FmtFsFd(IValueT Opcode, FPInstDataFormat Format,
310 const Operand *OpFd, const Operand *OpFs,
311 const char *InsnName) {
312 const IValueT Fd = encodeFPRegister(OpFd, "Fd", InsnName);
313 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName);
314
315 Opcode |= Fd << 6;
316 Opcode |= Fs << 11;
317 Opcode |= Format << 21;
318
319 emitInst(Opcode);
320}
321
322void AssemblerMIPS32::emitCOP1FmtFtFsFd(IValueT Opcode, FPInstDataFormat Format,
323 const Operand *OpFd,
324 const Operand *OpFs,
325 const Operand *OpFt,
326 const char *InsnName) {
327 const IValueT Fd = encodeFPRegister(OpFd, "Fd", InsnName);
328 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName);
329 const IValueT Ft = encodeFPRegister(OpFt, "Ft", InsnName);
330
331 Opcode |= Fd << 6;
332 Opcode |= Fs << 11;
333 Opcode |= Ft << 16;
334 Opcode |= Format << 21;
335
336 emitInst(Opcode);
337}
338
339void AssemblerMIPS32::emitCOP1FmtRtFsFd(IValueT Opcode, FPInstDataFormat Format,
340 const Operand *OpFd,
341 const Operand *OpFs,
342 const Operand *OpRt,
343 const char *InsnName) {
344 const IValueT Fd = encodeFPRegister(OpFd, "Fd", InsnName);
345 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName);
346 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
347
348 Opcode |= Fd << 6;
349 Opcode |= Fs << 11;
350 Opcode |= Rt << 16;
351 Opcode |= Format << 21;
352
353 emitInst(Opcode);
354}
355
356void AssemblerMIPS32::emitCOP1MovRtFs(IValueT Opcode, const Operand *OpRt,
357 const Operand *OpFs,
358 const char *InsnName) {
359 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
360 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName);
361 Opcode |= Fs << 11;
362 Opcode |= Rt << 16;
363
364 emitInst(Opcode);
365}
366
367void AssemblerMIPS32::abs_d(const Operand *OpFd, const Operand *OpFs) {
368 static constexpr IValueT Opcode = 0x44000005;
369 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "abs.d");
370}
371
372void AssemblerMIPS32::abs_s(const Operand *OpFd, const Operand *OpFs) {
373 static constexpr IValueT Opcode = 0x44000005;
374 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "abs.s");
375}
376
Jaydeep Patil130aca72016-10-28 05:30:54 -0700377void AssemblerMIPS32::addi(const Operand *OpRt, const Operand *OpRs,
378 const uint32_t Imm) {
379 static constexpr IValueT Opcode = 0x20000000;
380 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "addi");
381}
382
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700383void AssemblerMIPS32::add_d(const Operand *OpFd, const Operand *OpFs,
384 const Operand *OpFt) {
385 static constexpr IValueT Opcode = 0x44000000;
386 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "add.d");
387}
388
389void AssemblerMIPS32::add_s(const Operand *OpFd, const Operand *OpFs,
390 const Operand *OpFt) {
391 static constexpr IValueT Opcode = 0x44000000;
392 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "add.s");
393}
394
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700395void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs,
396 const uint32_t Imm) {
397 static constexpr IValueT Opcode = 0x24000000;
398 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "addiu");
399}
400
Jaydeep Patil130aca72016-10-28 05:30:54 -0700401void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs,
402 const Operand *OpImm, const RelocOp Reloc) {
403 static constexpr IValueT Opcode = 0x24000000;
404 emitRtRsImm16Rel(Opcode, OpRt, OpRs, OpImm, Reloc, "addiu");
405}
406
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700407void AssemblerMIPS32::addu(const Operand *OpRd, const Operand *OpRs,
408 const Operand *OpRt) {
409 static constexpr IValueT Opcode = 0x00000021;
410 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "addu");
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700411}
412
413void AssemblerMIPS32::and_(const Operand *OpRd, const Operand *OpRs,
414 const Operand *OpRt) {
415 static constexpr IValueT Opcode = 0x00000024;
416 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "and");
417}
418
419void AssemblerMIPS32::andi(const Operand *OpRt, const Operand *OpRs,
420 const uint32_t Imm) {
421 static constexpr IValueT Opcode = 0x30000000;
422 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "andi");
423}
424
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700425void AssemblerMIPS32::b(Label *TargetLabel) {
426 static constexpr Operand *OpRsNone = nullptr;
427 static constexpr Operand *OpRtNone = nullptr;
428 if (TargetLabel->isBound()) {
429 const int32_t Dest = TargetLabel->getPosition() - Buffer.size();
430 emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, Dest);
431 return;
432 }
433 const IOffsetT Position = Buffer.size();
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -0800434 IOffsetT PrevPosition = TargetLabel->getEncodedPosition();
435 if (PrevPosition != 0)
436 PrevPosition = Position - PrevPosition;
437 emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, PrevPosition);
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700438 TargetLabel->linkTo(*this, Position);
439}
440
Srdjan Obucina8d16c1d2016-09-20 08:44:44 -0700441void AssemblerMIPS32::c_eq_d(const Operand *OpFs, const Operand *OpFt) {
442 static constexpr IValueT Opcode = 0x44000032;
443 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
444 "c.eq.d");
445}
446
447void AssemblerMIPS32::c_eq_s(const Operand *OpFs, const Operand *OpFt) {
448 static constexpr IValueT Opcode = 0x44000032;
449 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
450 "c.eq.s");
451}
452
453void AssemblerMIPS32::c_ole_d(const Operand *OpFs, const Operand *OpFt) {
454 static constexpr IValueT Opcode = 0x44000036;
455 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
456 "c.ole.d");
457}
458
459void AssemblerMIPS32::c_ole_s(const Operand *OpFs, const Operand *OpFt) {
460 static constexpr IValueT Opcode = 0x44000036;
461 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
462 "c.ole.s");
463}
464
465void AssemblerMIPS32::c_olt_d(const Operand *OpFs, const Operand *OpFt) {
466 static constexpr IValueT Opcode = 0x44000034;
467 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
468 "c.olt.d");
469}
470
471void AssemblerMIPS32::c_olt_s(const Operand *OpFs, const Operand *OpFt) {
472 static constexpr IValueT Opcode = 0x44000034;
473 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
474 "c.olt.s");
475}
476
477void AssemblerMIPS32::c_ueq_d(const Operand *OpFs, const Operand *OpFt) {
478 static constexpr IValueT Opcode = 0x44000033;
479 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
480 "c.ueq.d");
481}
482
483void AssemblerMIPS32::c_ueq_s(const Operand *OpFs, const Operand *OpFt) {
484 static constexpr IValueT Opcode = 0x44000033;
485 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
486 "c.ueq.s");
487}
488
489void AssemblerMIPS32::c_ule_d(const Operand *OpFs, const Operand *OpFt) {
490 static constexpr IValueT Opcode = 0x44000037;
491 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
492 "c.ule.d");
493}
494
495void AssemblerMIPS32::c_ule_s(const Operand *OpFs, const Operand *OpFt) {
496 static constexpr IValueT Opcode = 0x44000037;
497 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
498 "c.ule.s");
499}
500
501void AssemblerMIPS32::c_ult_d(const Operand *OpFs, const Operand *OpFt) {
502 static constexpr IValueT Opcode = 0x44000035;
503 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
504 "c.ult.d");
505}
506
507void AssemblerMIPS32::c_ult_s(const Operand *OpFs, const Operand *OpFt) {
508 static constexpr IValueT Opcode = 0x44000035;
509 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
510 "c.ult.s");
511}
512
513void AssemblerMIPS32::c_un_d(const Operand *OpFs, const Operand *OpFt) {
514 static constexpr IValueT Opcode = 0x44000031;
515 emitCOP1Fcmp(Opcode, DoublePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
516 "c.un.d");
517}
518
519void AssemblerMIPS32::c_un_s(const Operand *OpFs, const Operand *OpFt) {
520 static constexpr IValueT Opcode = 0x44000031;
521 emitCOP1Fcmp(Opcode, SinglePrecision, OpFs, OpFt, OperandMIPS32FCC::FCC0,
522 "c.un.s");
523}
524
Srdjan Obucinad27ce3d2016-09-22 12:56:12 -0700525void AssemblerMIPS32::clz(const Operand *OpRd, const Operand *OpRs) {
526 IValueT Opcode = 0x70000020;
527 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "clz");
528 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "clz");
529 Opcode |= Rd << 11;
530 Opcode |= Rd << 16;
531 Opcode |= Rs << 21;
532 emitInst(Opcode);
533}
534
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700535void AssemblerMIPS32::cvt_d_l(const Operand *OpFd, const Operand *OpFs) {
536 static constexpr IValueT Opcode = 0x44000021;
537 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.d.l");
538}
539
540void AssemblerMIPS32::cvt_d_s(const Operand *OpFd, const Operand *OpFs) {
541 static constexpr IValueT Opcode = 0x44000021;
542 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "cvt.d.s");
543}
544
545void AssemblerMIPS32::cvt_d_w(const Operand *OpFd, const Operand *OpFs) {
546 static constexpr IValueT Opcode = 0x44000021;
547 emitCOP1FmtFsFd(Opcode, Word, OpFd, OpFs, "cvt.d.w");
548}
549
550void AssemblerMIPS32::cvt_s_d(const Operand *OpFd, const Operand *OpFs) {
551 static constexpr IValueT Opcode = 0x44000020;
552 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "cvt.s.d");
553}
554
555void AssemblerMIPS32::cvt_s_l(const Operand *OpFd, const Operand *OpFs) {
556 static constexpr IValueT Opcode = 0x44000020;
557 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.s.l");
558}
559
560void AssemblerMIPS32::cvt_s_w(const Operand *OpFd, const Operand *OpFs) {
561 static constexpr IValueT Opcode = 0x44000020;
562 emitCOP1FmtFsFd(Opcode, Word, OpFd, OpFs, "cvt.s.w");
563}
564
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700565void AssemblerMIPS32::div(const Operand *OpRs, const Operand *OpRt) {
566 static constexpr IValueT Opcode = 0x0000001A;
567 emitRsRt(Opcode, OpRs, OpRt, "div");
568}
569
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700570void AssemblerMIPS32::div_d(const Operand *OpFd, const Operand *OpFs,
571 const Operand *OpFt) {
572 static constexpr IValueT Opcode = 0x44000003;
573 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "div.d");
574}
575
576void AssemblerMIPS32::div_s(const Operand *OpFd, const Operand *OpFs,
577 const Operand *OpFt) {
578 static constexpr IValueT Opcode = 0x44000003;
579 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "div.s");
580}
581
Srdjan Obucina6163c622016-09-27 20:38:30 -0700582void AssemblerMIPS32::divu(const Operand *OpRs, const Operand *OpRt) {
583 static constexpr IValueT Opcode = 0x0000001B;
584 emitRsRt(Opcode, OpRs, OpRt, "divu");
585}
586
Jaydeep Patil130aca72016-10-28 05:30:54 -0700587MIPS32Fixup *AssemblerMIPS32::createMIPS32Fixup(const RelocOp Reloc,
588 const Constant *RelOp) {
589 MIPS32Fixup *Fixup = new (allocate<MIPS32Fixup>()) MIPS32Fixup();
590 switch (Reloc) {
591 case RelocOp::RO_Hi:
592 Fixup->set_kind(llvm::ELF::R_MIPS_HI16);
593 break;
594 case RelocOp::RO_Lo:
595 Fixup->set_kind(llvm::ELF::R_MIPS_LO16);
596 break;
597 case RelocOp::RO_Jal:
598 Fixup->set_kind(llvm::ELF::R_MIPS_26);
599 break;
600 default:
601 llvm::report_fatal_error("Fixup: Invalid Reloc type");
602 break;
603 }
604 Fixup->set_value(RelOp);
605 Buffer.installFixup(Fixup);
606 return Fixup;
607}
608
609size_t MIPS32Fixup::emit(GlobalContext *Ctx, const Assembler &Asm) const {
610 if (!BuildDefs::dump())
611 return InstMIPS32::InstSize;
612 Ostream &Str = Ctx->getStrEmit();
613 IValueT Inst = Asm.load<IValueT>(position());
614 const auto Symbol = symbol().toString();
615 Str << "\t"
616 << ".word " << llvm::format_hex(Inst, 8) << " # ";
617 switch (kind()) {
618 case llvm::ELF::R_MIPS_HI16:
619 Str << "R_MIPS_HI16 ";
620 break;
621 case llvm::ELF::R_MIPS_LO16:
622 Str << "R_MIPS_LO16 ";
623 break;
624 case llvm::ELF::R_MIPS_26:
625 Str << "R_MIPS_26 ";
626 break;
627 default:
628 Str << "Unknown ";
629 break;
630 }
631 Str << Symbol << "\n";
632 return InstMIPS32::InstSize;
633}
634
635void MIPS32Fixup::emitOffset(Assembler *Asm) const {
636 const IValueT Inst = Asm->load<IValueT>(position());
637 IValueT ImmMask = 0;
638 const IValueT Imm = offset();
639 if (kind() == llvm::ELF::R_MIPS_26) {
640 ImmMask = 0x03FFFFFF;
641 } else {
642 ImmMask = 0x0000FFFF;
643 }
644 Asm->store(position(), (Inst & ~ImmMask) | (Imm & ImmMask));
645}
646
647void AssemblerMIPS32::jal(const ConstantRelocatable *Target) {
648 IValueT Opcode = 0x0C000000;
649 emitFixup(createMIPS32Fixup(RelocOp::RO_Jal, Target));
650 emitInst(Opcode);
651 nop();
652}
653
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -0700654void AssemblerMIPS32::jalr(const Operand *OpRs, const Operand *OpRd) {
655 IValueT Opcode = 0x00000009;
656 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "jalr");
657 const IValueT Rd =
658 (OpRd == nullptr) ? 31 : encodeGPRegister(OpRd, "Rd", "jalr");
Stefan Maksimovic8208e752016-11-22 10:25:37 -0800659 Opcode |= Rd << 11;
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -0700660 Opcode |= Rs << 21;
661 emitInst(Opcode);
662 nop();
663}
664
Jaydeep Patil130aca72016-10-28 05:30:54 -0700665void AssemblerMIPS32::lui(const Operand *OpRt, const Operand *OpImm,
666 const RelocOp Reloc) {
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700667 IValueT Opcode = 0x3C000000;
668 const IValueT Rt = encodeGPRegister(OpRt, "Rt", "lui");
Jaydeep Patil130aca72016-10-28 05:30:54 -0700669 IValueT Imm16 = 0;
670
671 if (const auto *OpRel = llvm::dyn_cast<ConstantRelocatable>(OpImm)) {
672 emitFixup(createMIPS32Fixup(Reloc, OpRel));
673 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(OpImm)) {
674 Imm16 = C32->getValue();
675 } else {
676 llvm::report_fatal_error("lui: Invalid 2nd operand");
677 }
678
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700679 Opcode |= Rt << 16;
Jaydeep Patil130aca72016-10-28 05:30:54 -0700680 Opcode |= Imm16;
681 emitInst(Opcode);
682}
683
684void AssemblerMIPS32::ldc1(const Operand *OpRt, const Operand *OpBase,
685 const Operand *OpOff, const RelocOp Reloc) {
686 IValueT Opcode = 0xD4000000;
687 const IValueT Rt = encodeFPRegister(OpRt, "Ft", "ldc1");
688 const IValueT Base = encodeGPRegister(OpBase, "Base", "ldc1");
689 IValueT Imm16 = 0;
690
691 if (const auto *OpRel = llvm::dyn_cast<ConstantRelocatable>(OpOff)) {
692 emitFixup(createMIPS32Fixup(Reloc, OpRel));
693 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(OpOff)) {
694 Imm16 = C32->getValue();
695 } else {
696 llvm::report_fatal_error("ldc1: Invalid 2nd operand");
697 }
698
699 Opcode |= Base << 21;
700 Opcode |= Rt << 16;
701 Opcode |= Imm16;
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700702 emitInst(Opcode);
703}
704
Sagar Thakurbecb85f2016-11-18 12:15:46 -0800705void AssemblerMIPS32::ll(const Operand *OpRt, const Operand *OpBase,
706 const uint32_t Offset) {
707 static constexpr IValueT Opcode = 0xC0000000;
708 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "ll");
709}
710
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700711void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase,
712 const uint32_t Offset) {
713 switch (OpRt->getType()) {
714 case IceType_i1:
715 case IceType_i8: {
716 static constexpr IValueT Opcode = 0x80000000;
717 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lb");
Srdjan Obucina6ee373f2016-09-22 22:01:51 -0700718 break;
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700719 }
720 case IceType_i16: {
721 static constexpr IValueT Opcode = 0x84000000;
722 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lh");
Srdjan Obucina6ee373f2016-09-22 22:01:51 -0700723 break;
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700724 }
725 case IceType_i32: {
726 static constexpr IValueT Opcode = 0x8C000000;
727 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lw");
728 break;
729 }
730 case IceType_f32: {
731 static constexpr IValueT Opcode = 0xC4000000;
732 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "lwc1");
Srdjan Obucina6ee373f2016-09-22 22:01:51 -0700733 break;
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700734 }
735 case IceType_f64: {
736 static constexpr IValueT Opcode = 0xD4000000;
737 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "ldc1");
738 break;
739 }
740 default: { UnimplementedError(getFlags()); }
741 }
742}
743
Jaydeep Patil130aca72016-10-28 05:30:54 -0700744void AssemblerMIPS32::lwc1(const Operand *OpRt, const Operand *OpBase,
745 const Operand *OpOff, const RelocOp Reloc) {
746 IValueT Opcode = 0xC4000000;
747 const IValueT Rt = encodeFPRegister(OpRt, "Ft", "lwc1");
748 const IValueT Base = encodeGPRegister(OpBase, "Base", "lwc1");
749 IValueT Imm16 = 0;
750
751 if (const auto *OpRel = llvm::dyn_cast<ConstantRelocatable>(OpOff)) {
752 emitFixup(createMIPS32Fixup(Reloc, OpRel));
753 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(OpOff)) {
754 Imm16 = C32->getValue();
755 } else {
756 llvm::report_fatal_error("lwc1: Invalid 2nd operand");
757 }
758
759 Opcode |= Base << 21;
760 Opcode |= Rt << 16;
761 Opcode |= Imm16;
762 emitInst(Opcode);
763}
764
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700765void AssemblerMIPS32::mfc1(const Operand *OpRt, const Operand *OpFs) {
766 static constexpr IValueT Opcode = 0x44000000;
767 emitCOP1MovRtFs(Opcode, OpRt, OpFs, "mfc1");
768}
769
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700770void AssemblerMIPS32::mfhi(const Operand *OpRd) {
771 IValueT Opcode = 0x000000010;
772 IValueT Rd = encodeGPRegister(OpRd, "Rd", "mfhi");
773 Opcode |= Rd << 11;
774 emitInst(Opcode);
775}
776
777void AssemblerMIPS32::mflo(const Operand *OpRd) {
778 IValueT Opcode = 0x000000012;
779 IValueT Rd = encodeGPRegister(OpRd, "Rd", "mflo");
780 Opcode |= Rd << 11;
781 emitInst(Opcode);
782}
783
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700784void AssemblerMIPS32::mov_d(const Operand *OpFd, const Operand *OpFs) {
785 static constexpr IValueT Opcode = 0x44000006;
786 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "mov.d");
787}
788
789void AssemblerMIPS32::mov_s(const Operand *OpFd, const Operand *OpFs) {
790 static constexpr IValueT Opcode = 0x44000006;
791 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "mov.s");
792}
793
794void AssemblerMIPS32::move(const Operand *OpRd, const Operand *OpRs) {
795
796 const Type DstType = OpRd->getType();
797 const Type SrcType = OpRs->getType();
798
799 if ((isScalarIntegerType(DstType) && isScalarFloatingType(SrcType)) ||
800 (isScalarFloatingType(DstType) && isScalarIntegerType(SrcType))) {
801 if (isScalarFloatingType(DstType)) {
Jaydeep Patil130aca72016-10-28 05:30:54 -0700802 mtc1(OpRs, OpRd);
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700803 } else {
804 mfc1(OpRd, OpRs);
805 }
806 } else {
807 switch (DstType) {
808 case IceType_f32:
809 mov_s(OpRd, OpRs);
810 break;
811 case IceType_f64:
812 mov_d(OpRd, OpRs);
813 break;
814 case IceType_i1:
815 case IceType_i8:
816 case IceType_i16:
817 case IceType_i32: {
818 IValueT Opcode = 0x00000021;
819 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "pseudo-move");
820 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "pseudo-move");
821 const IValueT Rt = 0; // $0
822 Opcode |= Rs << 21;
823 Opcode |= Rt << 16;
824 Opcode |= Rd << 11;
825 emitInst(Opcode);
826 break;
827 }
828 default: { UnimplementedError(getFlags()); }
829 }
830 }
831}
832
Srdjan Obucina8d16c1d2016-09-20 08:44:44 -0700833void AssemblerMIPS32::movf(const Operand *OpRd, const Operand *OpRs,
834 const Operand *OpCc) {
835 IValueT Opcode = 0x00000001;
836 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "movf");
837 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "movf");
838 OperandMIPS32FCC::FCC Cc = OperandMIPS32FCC::FCC0;
839 if (const auto *OpFCC = llvm::dyn_cast<OperandMIPS32FCC>(OpCc)) {
840 Cc = OpFCC->getFCC();
841 }
842 const IValueT InstEncodingFalse = 0;
843 Opcode |= Rd << 11;
844 Opcode |= InstEncodingFalse << 16;
845 Opcode |= Cc << 18;
846 Opcode |= Rs << 21;
847 emitInst(Opcode);
848}
849
Srdjan Obucinad27ce3d2016-09-22 12:56:12 -0700850void AssemblerMIPS32::movn(const Operand *OpRd, const Operand *OpRs,
851 const Operand *OpRt) {
Srdjan Obucina6fd9c0e2016-09-26 20:58:17 -0700852 static constexpr IValueT Opcode = 0x0000000B;
Srdjan Obucinad27ce3d2016-09-22 12:56:12 -0700853 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "movn");
854}
855
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700856void AssemblerMIPS32::movn_d(const Operand *OpFd, const Operand *OpFs,
857 const Operand *OpFt) {
858 static constexpr IValueT Opcode = 0x44000013;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -0800859 emitCOP1FmtRtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "movn.d");
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700860}
861
862void AssemblerMIPS32::movn_s(const Operand *OpFd, const Operand *OpFs,
863 const Operand *OpFt) {
864 static constexpr IValueT Opcode = 0x44000013;
Jaydeep Patil0c4c07d2016-11-01 23:53:52 -0700865 emitCOP1FmtRtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "movn.s");
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700866}
867
Srdjan Obucina8d16c1d2016-09-20 08:44:44 -0700868void AssemblerMIPS32::movt(const Operand *OpRd, const Operand *OpRs,
869 const Operand *OpCc) {
870 IValueT Opcode = 0x00000001;
Jaydeep Patild8954472016-09-21 06:24:41 -0700871 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "movt");
872 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "movt");
Srdjan Obucina8d16c1d2016-09-20 08:44:44 -0700873 OperandMIPS32FCC::FCC Cc = OperandMIPS32FCC::FCC0;
874 if (const auto *OpFCC = llvm::dyn_cast<OperandMIPS32FCC>(OpCc)) {
875 Cc = OpFCC->getFCC();
876 }
877 const IValueT InstEncodingTrue = 1;
878 Opcode |= Rd << 11;
879 Opcode |= InstEncodingTrue << 16;
880 Opcode |= Cc << 18;
881 Opcode |= Rs << 21;
882 emitInst(Opcode);
883}
884
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700885void AssemblerMIPS32::movz_d(const Operand *OpFd, const Operand *OpFs,
886 const Operand *OpFt) {
887 static constexpr IValueT Opcode = 0x44000012;
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -0800888 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "movz.d");
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700889}
890
Srdjan Obucinab0f09fc2016-09-27 20:43:11 -0700891void AssemblerMIPS32::movz(const Operand *OpRd, const Operand *OpRs,
892 const Operand *OpRt) {
893 static constexpr IValueT Opcode = 0x0000000A;
894 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "movz");
895}
896
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700897void AssemblerMIPS32::movz_s(const Operand *OpFd, const Operand *OpFs,
898 const Operand *OpFt) {
899 static constexpr IValueT Opcode = 0x44000012;
900 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "movz.s");
901}
902
903void AssemblerMIPS32::mtc1(const Operand *OpRt, const Operand *OpFs) {
904 static constexpr IValueT Opcode = 0x44800000;
905 emitCOP1MovRtFs(Opcode, OpRt, OpFs, "mtc1");
906}
907
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700908void AssemblerMIPS32::mthi(const Operand *OpRs) {
909 IValueT Opcode = 0x000000011;
910 IValueT Rs = encodeGPRegister(OpRs, "Rs", "mthi");
911 Opcode |= Rs << 21;
912 emitInst(Opcode);
913}
914
915void AssemblerMIPS32::mtlo(const Operand *OpRs) {
916 IValueT Opcode = 0x000000013;
917 IValueT Rs = encodeGPRegister(OpRs, "Rs", "mtlo");
918 Opcode |= Rs << 21;
919 emitInst(Opcode);
920}
921
922void AssemblerMIPS32::mul(const Operand *OpRd, const Operand *OpRs,
923 const Operand *OpRt) {
924 static constexpr IValueT Opcode = 0x70000002;
925 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "mul");
926}
927
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700928void AssemblerMIPS32::mul_d(const Operand *OpFd, const Operand *OpFs,
929 const Operand *OpFt) {
930 static constexpr IValueT Opcode = 0x44000002;
931 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "mul.d");
932}
933
934void AssemblerMIPS32::mul_s(const Operand *OpFd, const Operand *OpFs,
935 const Operand *OpFt) {
936 static constexpr IValueT Opcode = 0x44000002;
937 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "mul.s");
938}
939
Jaydeep Patil130aca72016-10-28 05:30:54 -0700940void AssemblerMIPS32::mult(const Operand *OpRs, const Operand *OpRt) {
941 static constexpr IValueT Opcode = 0x00000018;
942 emitRsRt(Opcode, OpRs, OpRt, "mult");
943}
944
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700945void AssemblerMIPS32::multu(const Operand *OpRs, const Operand *OpRt) {
946 static constexpr IValueT Opcode = 0x00000019;
947 emitRsRt(Opcode, OpRs, OpRt, "multu");
948}
949
Srdjan Obucinacadda792016-09-22 11:24:44 -0700950void AssemblerMIPS32::nor(const Operand *OpRd, const Operand *OpRs,
951 const Operand *OpRt) {
952 static constexpr IValueT Opcode = 0x00000027;
953 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "nor");
954}
955
Jaydeep Patil135f5db2016-08-29 05:14:05 -0700956void AssemblerMIPS32::or_(const Operand *OpRd, const Operand *OpRs,
957 const Operand *OpRt) {
958 static constexpr IValueT Opcode = 0x00000025;
959 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "or");
960}
961
962void AssemblerMIPS32::ori(const Operand *OpRt, const Operand *OpRs,
963 const uint32_t Imm) {
964 static constexpr IValueT Opcode = 0x34000000;
965 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "ori");
966}
967
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700968void AssemblerMIPS32::ret(void) {
969 static constexpr IValueT Opcode = 0x03E00008; // JR $31
970 emitInst(Opcode);
971 nop(); // delay slot
972}
973
Sagar Thakurbecb85f2016-11-18 12:15:46 -0800974void AssemblerMIPS32::sc(const Operand *OpRt, const Operand *OpBase,
975 const uint32_t Offset) {
976 static constexpr IValueT Opcode = 0xE0000000;
977 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sc");
978}
979
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700980void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt,
981 const uint32_t Sa) {
982 static constexpr IValueT Opcode = 0x00000000;
983 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sll");
984}
985
Srdjan Obucina623f8ce2016-09-26 20:03:20 -0700986void AssemblerMIPS32::sllv(const Operand *OpRd, const Operand *OpRt,
987 const Operand *OpRs) {
988 static constexpr IValueT Opcode = 0x00000004;
989 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "sllv");
990}
991
Srdjan Obucina132ea7a2016-09-18 07:30:19 -0700992void AssemblerMIPS32::slt(const Operand *OpRd, const Operand *OpRs,
993 const Operand *OpRt) {
994 static constexpr IValueT Opcode = 0x0000002A;
995 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "slt");
996}
997
998void AssemblerMIPS32::slti(const Operand *OpRt, const Operand *OpRs,
999 const uint32_t Imm) {
1000 static constexpr IValueT Opcode = 0x28000000;
1001 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "slti");
1002}
1003
1004void AssemblerMIPS32::sltu(const Operand *OpRd, const Operand *OpRs,
1005 const Operand *OpRt) {
1006 static constexpr IValueT Opcode = 0x0000002B;
1007 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "sltu");
1008}
1009
1010void AssemblerMIPS32::sltiu(const Operand *OpRt, const Operand *OpRs,
1011 const uint32_t Imm) {
1012 static constexpr IValueT Opcode = 0x2c000000;
1013 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "sltiu");
1014}
1015
1016void AssemblerMIPS32::sqrt_d(const Operand *OpFd, const Operand *OpFs) {
1017 static constexpr IValueT Opcode = 0x44000004;
1018 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "sqrt.d");
1019}
1020
1021void AssemblerMIPS32::sqrt_s(const Operand *OpFd, const Operand *OpFs) {
1022 static constexpr IValueT Opcode = 0x44000004;
1023 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "sqrt.s");
1024}
1025
1026void AssemblerMIPS32::sra(const Operand *OpRd, const Operand *OpRt,
1027 const uint32_t Sa) {
1028 static constexpr IValueT Opcode = 0x00000003;
1029 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sra");
1030}
1031
1032void AssemblerMIPS32::srl(const Operand *OpRd, const Operand *OpRt,
1033 const uint32_t Sa) {
1034 static constexpr IValueT Opcode = 0x00000002;
1035 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "srl");
1036}
1037
Srdjan Obucinafe93fdd2016-09-28 06:38:44 -07001038void AssemblerMIPS32::srav(const Operand *OpRd, const Operand *OpRt,
1039 const Operand *OpRs) {
1040 static constexpr IValueT Opcode = 0x00000007;
1041 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "srav");
1042}
1043
Srdjan Obucina623f8ce2016-09-26 20:03:20 -07001044void AssemblerMIPS32::srlv(const Operand *OpRd, const Operand *OpRt,
1045 const Operand *OpRs) {
1046 static constexpr IValueT Opcode = 0x00000006;
1047 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "srlv");
1048}
1049
Srdjan Obucina132ea7a2016-09-18 07:30:19 -07001050void AssemblerMIPS32::sub_d(const Operand *OpFd, const Operand *OpFs,
1051 const Operand *OpFt) {
1052 static constexpr IValueT Opcode = 0x44000001;
1053 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "sub.d");
1054}
1055
1056void AssemblerMIPS32::sub_s(const Operand *OpFd, const Operand *OpFs,
1057 const Operand *OpFt) {
1058 static constexpr IValueT Opcode = 0x44000001;
1059 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "sub.s");
1060}
1061
Srdjan Obucina0a7f99d2016-09-23 06:59:50 -07001062void AssemblerMIPS32::subu(const Operand *OpRd, const Operand *OpRs,
1063 const Operand *OpRt) {
1064 static constexpr IValueT Opcode = 0x00000023;
1065 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "subu");
1066}
1067
Jaydeep Patil130aca72016-10-28 05:30:54 -07001068void AssemblerMIPS32::sdc1(const Operand *OpRt, const Operand *OpBase,
1069 const Operand *OpOff, const RelocOp Reloc) {
1070 IValueT Opcode = 0xF4000000;
1071 const IValueT Rt = encodeFPRegister(OpRt, "Ft", "sdc1");
1072 const IValueT Base = encodeGPRegister(OpBase, "Base", "sdc1");
1073 IValueT Imm16 = 0;
1074
1075 if (const auto *OpRel = llvm::dyn_cast<ConstantRelocatable>(OpOff)) {
1076 emitFixup(createMIPS32Fixup(Reloc, OpRel));
1077 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(OpOff)) {
1078 Imm16 = C32->getValue();
1079 } else {
1080 llvm::report_fatal_error("sdc1: Invalid 2nd operand");
1081 }
1082
1083 Opcode |= Base << 21;
1084 Opcode |= Rt << 16;
1085 Opcode |= Imm16;
1086 emitInst(Opcode);
1087}
1088
Srdjan Obucina132ea7a2016-09-18 07:30:19 -07001089void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase,
1090 const uint32_t Offset) {
1091 switch (OpRt->getType()) {
1092 case IceType_i1:
1093 case IceType_i8: {
1094 static constexpr IValueT Opcode = 0xA0000000;
1095 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sb");
1096 break;
1097 }
1098 case IceType_i16: {
1099 static constexpr IValueT Opcode = 0xA4000000;
1100 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sh");
1101 break;
1102 }
1103 case IceType_i32: {
1104 static constexpr IValueT Opcode = 0xAC000000;
1105 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sw");
1106 break;
1107 }
1108 case IceType_f32: {
1109 static constexpr IValueT Opcode = 0xE4000000;
1110 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "swc1");
1111 break;
1112 }
1113 case IceType_f64: {
1114 static constexpr IValueT Opcode = 0xF4000000;
1115 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "sdc1");
1116 break;
1117 }
1118 default: { UnimplementedError(getFlags()); }
1119 }
1120}
1121
Jaydeep Patil130aca72016-10-28 05:30:54 -07001122void AssemblerMIPS32::swc1(const Operand *OpRt, const Operand *OpBase,
1123 const Operand *OpOff, const RelocOp Reloc) {
1124 IValueT Opcode = 0xE4000000;
1125 const IValueT Rt = encodeFPRegister(OpRt, "Ft", "swc1");
1126 const IValueT Base = encodeGPRegister(OpBase, "Base", "swc1");
1127 IValueT Imm16 = 0;
1128
1129 if (const auto *OpRel = llvm::dyn_cast<ConstantRelocatable>(OpOff)) {
1130 emitFixup(createMIPS32Fixup(Reloc, OpRel));
1131 } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(OpOff)) {
1132 Imm16 = C32->getValue();
1133 } else {
1134 llvm::report_fatal_error("swc1: Invalid 2nd operand");
1135 }
1136
1137 Opcode |= Base << 21;
1138 Opcode |= Rt << 16;
1139 Opcode |= Imm16;
1140 emitInst(Opcode);
1141}
1142
Sagar Thakurbecb85f2016-11-18 12:15:46 -08001143void AssemblerMIPS32::sync() {
1144 static constexpr IValueT Opcode = 0x0000000f;
1145 emitInst(Opcode);
1146}
1147
Srdjan Obucina3b61d702016-09-20 06:49:52 -07001148void AssemblerMIPS32::teq(const Operand *OpRs, const Operand *OpRt,
1149 const uint32_t TrapCode) {
1150 IValueT Opcode = 0x00000034;
1151 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "teq");
1152 const IValueT Rt = encodeGPRegister(OpRt, "Rt", "teq");
1153 Opcode |= (TrapCode & 0xFFFFF) << 6;
1154 Opcode |= Rt << 16;
1155 Opcode |= Rs << 21;
1156 emitInst(Opcode);
1157}
1158
Srdjan Obucina132ea7a2016-09-18 07:30:19 -07001159void AssemblerMIPS32::trunc_l_d(const Operand *OpFd, const Operand *OpFs) {
1160 static constexpr IValueT Opcode = 0x4400000D;
1161 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "trunc.l.d");
1162}
1163
1164void AssemblerMIPS32::trunc_l_s(const Operand *OpFd, const Operand *OpFs) {
1165 static constexpr IValueT Opcode = 0x4400000D;
1166 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "trunc.l.s");
1167}
1168
1169void AssemblerMIPS32::trunc_w_d(const Operand *OpFd, const Operand *OpFs) {
1170 static constexpr IValueT Opcode = 0x4400000D;
Jaydeep Patil130aca72016-10-28 05:30:54 -07001171 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "trunc.w.d");
Srdjan Obucina132ea7a2016-09-18 07:30:19 -07001172}
1173
1174void AssemblerMIPS32::trunc_w_s(const Operand *OpFd, const Operand *OpFs) {
1175 static constexpr IValueT Opcode = 0x4400000D;
Jaydeep Patil130aca72016-10-28 05:30:54 -07001176 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "trunc.w.s");
Srdjan Obucina132ea7a2016-09-18 07:30:19 -07001177}
1178
Jaydeep Patil135f5db2016-08-29 05:14:05 -07001179void AssemblerMIPS32::xor_(const Operand *OpRd, const Operand *OpRs,
1180 const Operand *OpRt) {
1181 static constexpr IValueT Opcode = 0x00000026;
1182 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "xor");
1183}
1184
1185void AssemblerMIPS32::xori(const Operand *OpRt, const Operand *OpRs,
1186 const uint32_t Imm) {
1187 static constexpr IValueT Opcode = 0x38000000;
1188 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "xori");
1189}
1190
Jaydeep Patil135f5db2016-08-29 05:14:05 -07001191void AssemblerMIPS32::emitBr(const CondMIPS32::Cond Cond, const Operand *OpRs,
1192 const Operand *OpRt, IOffsetT Offset) {
1193 IValueT Opcode = 0;
1194
1195 switch (Cond) {
1196 default:
1197 break;
1198 case CondMIPS32::AL:
1199 case CondMIPS32::EQ:
1200 case CondMIPS32::EQZ:
1201 Opcode = 0x10000000;
1202 break;
1203 case CondMIPS32::NE:
1204 case CondMIPS32::NEZ:
1205 Opcode = 0x14000000;
1206 break;
1207 case CondMIPS32::LEZ:
1208 Opcode = 0x18000000;
1209 break;
1210 case CondMIPS32::LTZ:
1211 Opcode = 0x04000000;
1212 break;
1213 case CondMIPS32::GEZ:
1214 Opcode = 0x04010000;
1215 break;
1216 case CondMIPS32::GTZ:
1217 Opcode = 0x1C000000;
1218 break;
1219 }
1220
1221 if (Opcode == 0) {
1222 llvm::report_fatal_error("Branch: Invalid condition");
1223 }
1224
1225 if (OpRs != nullptr) {
1226 IValueT Rs = encodeGPRegister(OpRs, "Rs", "branch");
1227 Opcode |= Rs << 21;
1228 }
1229
1230 if (OpRt != nullptr) {
1231 IValueT Rt = encodeGPRegister(OpRt, "Rt", "branch");
1232 Opcode |= Rt << 16;
1233 }
1234
1235 Opcode = encodeBranchOffset(Offset, Opcode);
1236 emitInst(Opcode);
1237 nop(); // delay slot
1238}
1239
Jaydeep Patil135f5db2016-08-29 05:14:05 -07001240void AssemblerMIPS32::bcc(const CondMIPS32::Cond Cond, const Operand *OpRs,
1241 const Operand *OpRt, Label *TargetLabel) {
1242 if (TargetLabel->isBound()) {
1243 const int32_t Dest = TargetLabel->getPosition() - Buffer.size();
1244 emitBr(Cond, OpRs, OpRt, Dest);
1245 return;
1246 }
1247 const IOffsetT Position = Buffer.size();
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001248 IOffsetT PrevPosition = TargetLabel->getEncodedPosition();
1249 if (PrevPosition != 0)
1250 PrevPosition = Position - PrevPosition;
1251 emitBr(Cond, OpRs, OpRt, PrevPosition);
Jaydeep Patil135f5db2016-08-29 05:14:05 -07001252 TargetLabel->linkTo(*this, Position);
1253}
1254
1255void AssemblerMIPS32::bzc(const CondMIPS32::Cond Cond, const Operand *OpRs,
1256 Label *TargetLabel) {
1257 static constexpr Operand *OpRtNone = nullptr;
1258 if (TargetLabel->isBound()) {
1259 const int32_t Dest = TargetLabel->getPosition() - Buffer.size();
1260 emitBr(Cond, OpRs, OpRtNone, Dest);
1261 return;
1262 }
1263 const IOffsetT Position = Buffer.size();
Jaydeep Patil2bbda7f2017-01-10 21:48:58 -08001264 IOffsetT PrevPosition = TargetLabel->getEncodedPosition();
1265 if (PrevPosition)
1266 PrevPosition = Position - PrevPosition;
1267 emitBr(Cond, OpRs, OpRtNone, PrevPosition);
Jaydeep Patil135f5db2016-08-29 05:14:05 -07001268 TargetLabel->linkTo(*this, Position);
1269}
1270
1271} // end of namespace MIPS32
1272} // end of namespace Ice