OLD | NEW |
---|---|
(Empty) | |
1 //===- subzero/src/IceAssemblerMIPS32.cpp - MIPS32 Assembler --*- C++ -*-====// | |
Jim Stichnoth
2016/08/24 15:37:38
I'm being super pedantic here, sorry...
The LLVM
jaydeep.patil
2016/08/25 04:39:08
Done.
| |
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 | |
20 namespace { | |
21 | |
22 using namespace Ice; | |
23 using namespace Ice::MIPS32; | |
24 | |
25 // Offset modifier to current PC for next instruction. | |
26 static constexpr IOffsetT kPCReadOffset = 4; | |
27 | |
28 // Mask to pull out PC offset from branch instruction. | |
29 static constexpr int kBranchOffsetBits = 16; | |
30 static constexpr IOffsetT kBranchOffsetMask = 0x0000ffff; | |
31 | |
32 } // end of anonymous namespace | |
33 | |
34 namespace Ice { | |
35 namespace MIPS32 { | |
36 | |
37 void 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 | |
46 namespace { | |
47 | |
48 // TEQ $0, $0 - Trap if equal | |
49 static constexpr uint8_t TrapBytesRaw[] = {0x00, 0x00, 0x00, 0x34}; | |
50 | |
51 const auto TrapBytes = | |
52 llvm::ArrayRef<uint8_t>(TrapBytesRaw, llvm::array_lengthof(TrapBytesRaw)); | |
53 | |
54 } // end of anonymous namespace | |
55 | |
56 llvm::ArrayRef<uint8_t> AssemblerMIPS32::getNonExecBundlePadding() const { | |
57 return TrapBytes; | |
58 } | |
59 | |
60 void AssemblerMIPS32::trap() { | |
61 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | |
62 for (const uint8_t &Byte : reverse_range(TrapBytes)) | |
63 Buffer.emit<uint8_t>(Byte); | |
64 } | |
65 | |
66 void AssemblerMIPS32::nop() { emitInst(0); } | |
67 | |
68 void 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 | |
76 Label *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 | |
94 void 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 | |
105 // Checks that Offset can fit in imm16 constant of branch instruction. | |
106 void assertCanEncodeBranchOffset(IOffsetT Offset) { | |
107 (void)Offset; | |
108 (void)kBranchOffsetBits; | |
109 assert(Utils::IsAligned(Offset, 4)); | |
110 assert(Utils::IsInt(kBranchOffsetBits, Offset >> 2)); | |
111 } | |
112 | |
113 IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) { | |
114 Offset -= kPCReadOffset; | |
115 assertCanEncodeBranchOffset(Offset); | |
116 Offset >>= 2; | |
117 Offset &= kBranchOffsetMask; | |
118 return (Inst & ~kBranchOffsetMask) | Offset; | |
119 } | |
120 | |
121 IOffsetT AssemblerMIPS32::decodeBranchOffset(IValueT Inst) { | |
122 int16_t imm = (Inst & kBranchOffsetMask); | |
123 IOffsetT Offset = imm; | |
124 Offset = Offset << 2; | |
125 return (Offset + kPCReadOffset); | |
126 } | |
127 | |
128 void AssemblerMIPS32::bind(Label *L) { | |
129 IOffsetT BoundPc = Buffer.size(); | |
130 assert(!L->isBound()); // Labels can only be bound once. | |
131 while (L->isLinked()) { | |
132 IOffsetT Position = L->getLinkPosition(); | |
133 IOffsetT Dest = BoundPc - Position; | |
134 IValueT Inst = Buffer.load<IValueT>(Position); | |
135 Buffer.store<IValueT>(Position, encodeBranchOffset(Dest, Inst)); | |
136 L->setPosition(decodeBranchOffset(Inst)); | |
137 } | |
138 L->bindTo(BoundPc); | |
139 } | |
140 | |
141 enum RegSetWanted { WantGPRegs, WantFPRegs }; | |
142 | |
143 IValueT getEncodedGPRegNum(const Variable *Var) { | |
144 assert(Var->hasReg()); | |
145 const auto Reg = Var->getRegNum(); | |
146 return RegMIPS32::getEncodedGPR(Reg); | |
147 } | |
148 | |
149 bool encodeOperand(const Operand *Opnd, IValueT &Value, | |
150 RegSetWanted WantedRegSet) { | |
151 Value = 0; | |
152 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | |
153 if (Var->hasReg()) { | |
154 switch (WantedRegSet) { | |
155 case WantGPRegs: | |
156 Value = getEncodedGPRegNum(Var); | |
157 break; | |
158 default: | |
159 break; | |
160 } | |
161 return true; | |
162 } | |
163 return false; | |
164 } | |
165 return false; | |
166 } | |
167 | |
168 IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet, | |
169 const char *RegName, const char *InstName) { | |
170 IValueT Reg = 0; | |
171 if (encodeOperand(OpReg, Reg, WantedRegSet) != true) | |
172 llvm::report_fatal_error(std::string(InstName) + ": Can't find register " + | |
173 RegName); | |
174 return Reg; | |
175 } | |
176 | |
177 IValueT encodeGPRegister(const Operand *OpReg, const char *RegName, | |
178 const char *InstName) { | |
179 return encodeRegister(OpReg, WantGPRegs, RegName, InstName); | |
180 } | |
181 | |
182 void AssemblerMIPS32::emitRtRsImm16(IValueT Opcode, const Operand *OpRt, | |
183 const Operand *OpRs, const uint32_t Imm, | |
184 const char *InsnName) { | |
185 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | |
186 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); | |
187 | |
188 Opcode |= Rs << 21; | |
189 Opcode |= Rt << 16; | |
190 Opcode |= Imm & 0xffff; | |
191 | |
192 emitInst(Opcode); | |
193 } | |
194 | |
195 void AssemblerMIPS32::emitRdRtSa(IValueT Opcode, const Operand *OpRd, | |
196 const Operand *OpRt, const uint32_t Sa, | |
197 const char *InsnName) { | |
198 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); | |
199 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | |
200 | |
201 Opcode |= Rt << 16; | |
202 Opcode |= Rd << 11; | |
203 Opcode |= (Sa & 0x1f) << 6; | |
204 | |
205 emitInst(Opcode); | |
206 } | |
207 | |
208 void AssemblerMIPS32::emitRdRsRt(IValueT Opcode, const Operand *OpRd, | |
209 const Operand *OpRs, const Operand *OpRt, | |
210 const char *InsnName) { | |
211 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); | |
212 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); | |
213 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | |
214 | |
215 Opcode |= Rs << 21; | |
216 Opcode |= Rt << 16; | |
217 Opcode |= Rd << 11; | |
218 | |
219 emitInst(Opcode); | |
220 } | |
221 | |
222 void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs, | |
223 const uint32_t Imm) { | |
224 static constexpr IValueT Opcode = 0x24000000; | |
225 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "addiu"); | |
226 } | |
227 | |
228 void AssemblerMIPS32::slti(const Operand *OpRt, const Operand *OpRs, | |
229 const uint32_t Imm) { | |
230 static constexpr IValueT Opcode = 0x28000000; | |
231 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "slti"); | |
232 } | |
233 | |
234 void AssemblerMIPS32::sltiu(const Operand *OpRt, const Operand *OpRs, | |
235 const uint32_t Imm) { | |
236 static constexpr IValueT Opcode = 0x2c000000; | |
237 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "sltiu"); | |
238 } | |
239 | |
240 void AssemblerMIPS32::and_(const Operand *OpRd, const Operand *OpRs, | |
241 const Operand *OpRt) { | |
242 static constexpr IValueT Opcode = 0x00000024; | |
243 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "and"); | |
244 } | |
245 | |
246 void AssemblerMIPS32::andi(const Operand *OpRt, const Operand *OpRs, | |
247 const uint32_t Imm) { | |
248 static constexpr IValueT Opcode = 0x30000000; | |
249 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "andi"); | |
250 } | |
251 | |
252 void AssemblerMIPS32::or_(const Operand *OpRd, const Operand *OpRs, | |
253 const Operand *OpRt) { | |
254 static constexpr IValueT Opcode = 0x00000025; | |
255 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "or"); | |
256 } | |
257 | |
258 void AssemblerMIPS32::ori(const Operand *OpRt, const Operand *OpRs, | |
259 const uint32_t Imm) { | |
260 static constexpr IValueT Opcode = 0x34000000; | |
261 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "ori"); | |
262 } | |
263 | |
264 void AssemblerMIPS32::xor_(const Operand *OpRd, const Operand *OpRs, | |
265 const Operand *OpRt) { | |
266 static constexpr IValueT Opcode = 0x00000026; | |
267 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "xor"); | |
268 } | |
269 | |
270 void AssemblerMIPS32::xori(const Operand *OpRt, const Operand *OpRs, | |
271 const uint32_t Imm) { | |
272 static constexpr IValueT Opcode = 0x38000000; | |
273 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "xori"); | |
274 } | |
275 | |
276 void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt, | |
277 const uint32_t Sa) { | |
278 static constexpr IValueT Opcode = 0x00000000; | |
279 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sll"); | |
280 } | |
281 | |
282 void AssemblerMIPS32::srl(const Operand *OpRd, const Operand *OpRt, | |
283 const uint32_t Sa) { | |
284 static constexpr IValueT Opcode = 0x00000002; | |
285 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "srl"); | |
286 } | |
287 | |
288 void AssemblerMIPS32::sra(const Operand *OpRd, const Operand *OpRt, | |
289 const uint32_t Sa) { | |
290 static constexpr IValueT Opcode = 0x00000003; | |
291 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sra"); | |
292 } | |
293 | |
294 void AssemblerMIPS32::move(const Operand *OpRd, const Operand *OpRs) { | |
295 IValueT Opcode = 0x00000021; | |
296 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "pseudo-move"); | |
297 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "pseudo-move"); | |
298 const IValueT Rt = 0; // $0 | |
299 Opcode |= Rs << 21; | |
300 Opcode |= Rt << 16; | |
301 Opcode |= Rd << 11; | |
302 emitInst(Opcode); | |
303 } | |
304 | |
305 void AssemblerMIPS32::addu(const Operand *OpRd, const Operand *OpRs, | |
306 const Operand *OpRt) { | |
307 static constexpr IValueT Opcode = 0x00000021; | |
308 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "addu"); | |
309 } | |
310 | |
311 void AssemblerMIPS32::sltu(const Operand *OpRd, const Operand *OpRs, | |
312 const Operand *OpRt) { | |
313 static constexpr IValueT Opcode = 0x0000002B; | |
314 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "sltu"); | |
315 } | |
316 | |
317 void AssemblerMIPS32::slt(const Operand *OpRd, const Operand *OpRs, | |
318 const Operand *OpRt) { | |
319 static constexpr IValueT Opcode = 0x0000002A; | |
320 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "slt"); | |
321 } | |
322 | |
323 void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase, | |
324 const uint32_t Offset) { | |
325 static constexpr IValueT Opcode = 0xAC000000; | |
326 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sw"); | |
327 } | |
328 | |
329 void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase, | |
330 const uint32_t Offset) { | |
331 static constexpr IValueT Opcode = 0x8C000000; | |
332 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lw"); | |
333 } | |
334 | |
335 void AssemblerMIPS32::ret(void) { | |
336 static constexpr IValueT Opcode = 0x03E00008; // JR $31 | |
337 emitInst(Opcode); | |
338 nop(); // delay slot | |
339 } | |
340 | |
341 void AssemblerMIPS32::emitBr(const CondMIPS32::Cond Cond, const Operand *OpRs, | |
342 const Operand *OpRt, IOffsetT Offset) { | |
343 IValueT Opcode = 0; | |
344 | |
345 switch (Cond) { | |
346 default: | |
347 break; | |
348 case CondMIPS32::AL: | |
349 case CondMIPS32::EQ: | |
350 case CondMIPS32::EQZ: | |
351 Opcode = 0x10000000; | |
352 break; | |
353 case CondMIPS32::NE: | |
354 case CondMIPS32::NEZ: | |
355 Opcode = 0x14000000; | |
356 break; | |
357 case CondMIPS32::LEZ: | |
358 Opcode = 0x18000000; | |
359 break; | |
360 case CondMIPS32::LTZ: | |
361 Opcode = 0x04000000; | |
362 break; | |
363 case CondMIPS32::GEZ: | |
364 Opcode = 0x04010000; | |
365 break; | |
366 case CondMIPS32::GTZ: | |
367 Opcode = 0x1C000000; | |
368 break; | |
369 } | |
370 | |
371 if (Opcode == 0) { | |
372 llvm::report_fatal_error("Branch: Invalid condition"); | |
373 } | |
374 | |
375 if (OpRs != nullptr) { | |
376 IValueT Rs = encodeGPRegister(OpRs, "Rs", "branch"); | |
377 Opcode |= Rs << 21; | |
378 } | |
379 | |
380 if (OpRt != nullptr) { | |
381 IValueT Rt = encodeGPRegister(OpRt, "Rt", "branch"); | |
382 Opcode |= Rt << 16; | |
383 } | |
384 | |
385 Opcode = encodeBranchOffset(Offset, Opcode); | |
386 emitInst(Opcode); | |
387 nop(); // delay slot | |
388 } | |
389 | |
390 void AssemblerMIPS32::b(Label *TargetLabel) { | |
391 static constexpr Operand *OpRsNone = nullptr; | |
392 static constexpr Operand *OpRtNone = nullptr; | |
393 if (TargetLabel->isBound()) { | |
394 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | |
395 emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, Dest); | |
396 return; | |
397 } | |
398 const IOffsetT Position = Buffer.size(); | |
399 emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, TargetLabel->getEncodedPosition()); | |
400 TargetLabel->linkTo(*this, Position); | |
401 } | |
402 | |
403 void AssemblerMIPS32::bcc(const CondMIPS32::Cond Cond, const Operand *OpRs, | |
404 const Operand *OpRt, Label *TargetLabel) { | |
405 if (TargetLabel->isBound()) { | |
406 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | |
407 emitBr(Cond, OpRs, OpRt, Dest); | |
408 return; | |
409 } | |
410 const IOffsetT Position = Buffer.size(); | |
411 emitBr(Cond, OpRs, OpRt, TargetLabel->getEncodedPosition()); | |
412 TargetLabel->linkTo(*this, Position); | |
413 } | |
414 | |
415 void AssemblerMIPS32::bzc(const CondMIPS32::Cond Cond, const Operand *OpRs, | |
416 Label *TargetLabel) { | |
417 static constexpr Operand *OpRtNone = nullptr; | |
418 if (TargetLabel->isBound()) { | |
419 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | |
420 emitBr(Cond, OpRs, OpRtNone, Dest); | |
421 return; | |
422 } | |
423 const IOffsetT Position = Buffer.size(); | |
424 emitBr(Cond, OpRs, OpRtNone, TargetLabel->getEncodedPosition()); | |
425 TargetLabel->linkTo(*this, Position); | |
426 } | |
427 | |
428 } // end of namespace MIPS32 | |
429 } // end of namespace Ice | |
OLD | NEW |