OLD | NEW |
---|---|
(Empty) | |
1 //===- subzero/src/IceAssemblerMIPS32.cpp - Assembler for MIPS32 --*- C++ -*-=== // | |
Jim Stichnoth
2016/08/19 17:12:21
Fix 80-col here. May be easiest to change the des
| |
2 // | |
3 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
Jim Stichnoth
2016/08/19 17:12:21
For the x86 and ARM32 integrated assemblers, we st
| |
4 // for details. All rights reserved. Use of this source code is governed by a | |
5 // BSD-style license that can be found in the LICENSE file. | |
6 // | |
7 // Modified by the Subzero authors. | |
8 // | |
9 //===----------------------------------------------------------------------===// | |
10 // | |
11 // The Subzero Code Generator | |
12 // | |
13 // This file is distributed under the University of Illinois Open Source | |
14 // License. See LICENSE.TXT for details. | |
15 // | |
16 //===----------------------------------------------------------------------===// | |
17 /// | |
18 /// \file | |
19 /// \brief Implements the Assembler class for MIPS32. | |
20 /// | |
21 //===----------------------------------------------------------------------===// | |
22 | |
23 #include "IceAssemblerMIPS32.h" | |
24 #include "IceRegistersMIPS32.h" | |
25 #include "IceCfgNode.h" | |
Jim Stichnoth
2016/08/19 17:12:21
Can these be sorted alphabetically?
| |
26 #include "IceUtils.h" | |
27 | |
28 namespace { | |
29 | |
30 using namespace Ice; | |
31 using namespace Ice::MIPS32; | |
32 | |
33 //using WordType = uint32_t; | |
Jim Stichnoth
2016/08/19 17:12:21
Remove commented-out code?
| |
34 //static constexpr IValueT kWordSize = sizeof(WordType); | |
35 | |
36 // Offset modifier to current PC for next instruction. | |
37 static constexpr IOffsetT kPCReadOffset = 4; | |
38 | |
39 // Mask to pull out PC offset from branch instruction. | |
40 static constexpr int kBranchOffsetBits = 16; | |
41 static constexpr IOffsetT kBranchOffsetMask = 0x0000ffff; | |
42 | |
43 } // end of anonymous namespace | |
44 | |
45 namespace Ice { | |
46 namespace MIPS32 { | |
47 | |
48 void AssemblerMIPS32::emitTextInst(const std::string &Text, SizeT InstSize) { | |
49 AssemblerFixup *F = createTextFixup(Text, InstSize); | |
50 emitFixup(F); | |
51 for (SizeT I = 0; I < InstSize; ++I) { | |
52 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | |
53 Buffer.emit<char>(0); | |
54 } | |
55 } | |
56 | |
57 namespace { | |
58 | |
59 // TEQ $0, $0 - Trap if equal | |
60 const uint8_t TrapBytesRaw[] = {0x00, 0x00, 0x00, 0x34}; | |
Jim Stichnoth
2016/08/19 17:12:21
Can this be constexpr?
| |
61 | |
62 const auto TrapBytes = | |
63 llvm::ArrayRef<uint8_t>(TrapBytesRaw, llvm::array_lengthof(TrapBytesRaw)); | |
64 | |
65 } // end of anonymous namespace | |
66 | |
67 llvm::ArrayRef<uint8_t> AssemblerMIPS32::getNonExecBundlePadding() const { | |
68 return TrapBytes; | |
69 } | |
70 | |
71 void AssemblerMIPS32::trap() { | |
72 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | |
73 for (const uint8_t &Byte : reverse_range(TrapBytes)) | |
74 Buffer.emit<uint8_t>(Byte); | |
75 } | |
76 | |
77 void AssemblerMIPS32::nop() { | |
78 emitInst(0); | |
79 } | |
80 | |
81 void AssemblerMIPS32::padWithNop(intptr_t Padding) { | |
82 constexpr intptr_t InstWidth = sizeof(IValueT); | |
83 assert(Padding % InstWidth == 0 && | |
84 "Padding not multiple of instruction size"); | |
85 for (intptr_t i = 0; i < Padding; i += InstWidth) | |
86 nop(); | |
87 } | |
88 | |
89 Label *AssemblerMIPS32::getOrCreateLabel(SizeT Number, LabelVector &Labels) { | |
90 Label *L = nullptr; | |
91 if (Number == Labels.size()) { | |
92 L = new (this->allocate<Label>()) Label(); | |
93 Labels.push_back(L); | |
94 return L; | |
95 } | |
96 if (Number > Labels.size()) { | |
97 Labels.resize(Number + 1); | |
98 } | |
99 L = Labels[Number]; | |
100 if (!L) { | |
Jim Stichnoth
2016/08/19 17:12:21
L != nullptr
| |
101 L = new (this->allocate<Label>()) Label(); | |
102 Labels[Number] = L; | |
103 } | |
104 return L; | |
105 } | |
106 | |
107 void AssemblerMIPS32::bindCfgNodeLabel(const CfgNode *Node) { | |
108 if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) { | |
109 constexpr SizeT InstSize = 0; | |
110 emitTextInst(Node->getAsmName() + ":", InstSize); | |
111 } | |
112 SizeT NodeNumber = Node->getIndex(); | |
113 assert(!getPreliminary()); | |
114 Label *L = getOrCreateCfgNodeLabel(NodeNumber); | |
115 this->bind(L); | |
116 } | |
117 | |
118 // Checks that Offset can fit in imm16 constant of branch instruction. | |
119 void assertCanEncodeBranchOffset(IOffsetT Offset) { | |
120 (void)Offset; | |
121 (void)kBranchOffsetBits; | |
122 assert(Utils::IsAligned(Offset, 4) && | |
Jim Stichnoth
2016/08/19 17:12:21
Instead of:
assert(A & B);
use:
assert(A);
a
| |
123 Utils::IsInt(kBranchOffsetBits, Offset >> 2)); | |
124 } | |
125 | |
126 IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) { | |
127 Offset -= kPCReadOffset; | |
128 assertCanEncodeBranchOffset(Offset); | |
129 Offset >>= 2; | |
130 Offset &= kBranchOffsetMask; | |
131 return (Inst & ~kBranchOffsetMask) | Offset; | |
132 } | |
133 | |
134 IOffsetT AssemblerMIPS32::decodeBranchOffset(IValueT Inst) { | |
135 int16_t imm = (Inst & kBranchOffsetMask); | |
136 IOffsetT Offset = imm; | |
137 Offset = Offset << 2; | |
138 return (Offset + kPCReadOffset); | |
139 } | |
140 | |
141 void AssemblerMIPS32::bind(Label *L) { | |
142 IOffsetT BoundPc = Buffer.size(); | |
143 assert(!L->isBound()); // Labels can only be bound once. | |
144 while (L->isLinked()) { | |
145 IOffsetT Position = L->getLinkPosition(); | |
146 IOffsetT Dest = BoundPc - Position; | |
147 IValueT Inst = Buffer.load<IValueT>(Position); | |
148 Buffer.store<IValueT>(Position, encodeBranchOffset(Dest, Inst)); | |
149 L->setPosition(decodeBranchOffset(Inst)); | |
150 } | |
151 L->bindTo(BoundPc); | |
152 } | |
153 | |
154 enum RegSetWanted { WantGPRegs, WantFPRegs }; | |
155 | |
156 IValueT getEncodedGPRegNum(const Variable *Var) { | |
157 assert(Var->hasReg()); | |
158 const auto Reg = Var->getRegNum(); | |
159 return RegMIPS32::getEncodedGPR(Reg); | |
160 } | |
161 | |
162 bool encodeOperand(const Operand *Opnd, IValueT &Value, | |
163 RegSetWanted WantedRegSet) { | |
164 Value = 0; | |
165 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | |
166 if (Var->hasReg()) { | |
167 switch (WantedRegSet) { | |
168 case WantGPRegs: | |
169 Value = getEncodedGPRegNum(Var); | |
170 break; | |
171 default: | |
172 break; | |
173 } | |
174 return true; | |
175 } | |
176 return false; | |
177 } | |
178 return false; | |
179 } | |
180 | |
181 IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet, | |
182 const char *RegName, const char *InstName) { | |
183 IValueT Reg = 0; | |
184 if (encodeOperand(OpReg, Reg, WantedRegSet) != true) | |
185 llvm::report_fatal_error(std::string(InstName) + ": Can't find register " + | |
186 RegName); | |
187 return Reg; | |
188 } | |
189 | |
190 IValueT encodeGPRegister(const Operand *OpReg, const char *RegName, | |
191 const char *InstName) { | |
192 return encodeRegister(OpReg, WantGPRegs, RegName, InstName); | |
193 } | |
194 | |
195 void AssemblerMIPS32::emitRtRsImm16(IValueT Opcode, const Operand *OpRt, | |
196 const Operand *OpRs, const uint32_t Imm, | |
197 const char *InsnName) | |
198 { | |
199 IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | |
Jim Stichnoth
2016/08/19 17:12:21
const IValueT ...
here and wherever reasonable be
| |
200 IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); | |
201 | |
202 Opcode |= Rs << 21; | |
203 Opcode |= Rt << 16; | |
204 Opcode |= Imm & 0xffff; | |
205 | |
206 emitInst(Opcode); | |
207 } | |
208 | |
209 void AssemblerMIPS32::emitRdRtSa(IValueT Opcode, const Operand *OpRd, | |
210 const Operand *OpRt, const uint32_t Sa, | |
211 const char *InsnName) | |
212 { | |
213 IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); | |
214 IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | |
215 | |
216 Opcode |= Rt << 16; | |
217 Opcode |= Rd << 11; | |
218 Opcode |= (Sa & 0x1f) << 6; | |
219 | |
220 emitInst(Opcode); | |
221 } | |
222 | |
223 void AssemblerMIPS32::emitRdRsRt(IValueT Opcode, const Operand *OpRd, | |
224 const Operand *OpRs, const Operand *OpRt, | |
225 const char *InsnName) | |
226 { | |
227 IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); | |
228 IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); | |
229 IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | |
230 | |
231 Opcode |= Rs << 21; | |
232 Opcode |= Rt << 16; | |
233 Opcode |= Rd << 11; | |
234 | |
235 emitInst(Opcode); | |
236 } | |
237 | |
238 void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs, | |
239 const uint32_t Imm) | |
240 { | |
241 IValueT Opcode = 0x24000000; | |
Jim Stichnoth
2016/08/19 17:12:21
Here and below, for the Opcode declarations, use s
| |
242 emitRtRsImm16 (Opcode, OpRt, OpRs, Imm, "addiu"); | |
243 } | |
244 | |
245 void AssemblerMIPS32::slti(const Operand *OpRt, const Operand *OpRs, | |
246 const uint32_t Imm) | |
247 { | |
248 IValueT Opcode = 0x28000000; | |
249 emitRtRsImm16 (Opcode, OpRt, OpRs, Imm, "slti"); | |
250 } | |
251 | |
252 void AssemblerMIPS32::sltiu(const Operand *OpRt, const Operand *OpRs, | |
253 const uint32_t Imm) | |
254 { | |
255 IValueT Opcode = 0x2c000000; | |
256 emitRtRsImm16 (Opcode, OpRt, OpRs, Imm, "sltiu"); | |
257 } | |
258 | |
259 void AssemblerMIPS32::andi(const Operand *OpRt, const Operand *OpRs, | |
260 const uint32_t Imm) | |
261 { | |
262 IValueT Opcode = 0x30000000; | |
263 emitRtRsImm16 (Opcode, OpRt, OpRs, Imm, "andi"); | |
264 } | |
265 | |
266 void AssemblerMIPS32::ori(const Operand *OpRt, const Operand *OpRs, | |
267 const uint32_t Imm) | |
268 { | |
269 IValueT Opcode = 0x34000000; | |
270 emitRtRsImm16 (Opcode, OpRt, OpRs, Imm, "ori"); | |
271 } | |
272 | |
273 void AssemblerMIPS32::xori(const Operand *OpRt, const Operand *OpRs, | |
274 const uint32_t Imm) | |
275 { | |
276 IValueT Opcode = 0x38000000; | |
277 emitRtRsImm16 (Opcode, OpRt, OpRs, Imm, "xori"); | |
278 } | |
279 | |
280 void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt, | |
281 const uint32_t Sa) | |
282 { | |
283 IValueT Opcode = 0x00000000; | |
284 emitRdRtSa (Opcode, OpRd, OpRt, Sa, "sll"); | |
285 } | |
286 | |
287 void AssemblerMIPS32::srl(const Operand *OpRd, const Operand *OpRt, | |
288 const uint32_t Sa) | |
289 { | |
290 IValueT Opcode = 0x00000002; | |
291 emitRdRtSa (Opcode, OpRd, OpRt, Sa, "srl"); | |
292 } | |
293 | |
294 void AssemblerMIPS32::sra(const Operand *OpRd, const Operand *OpRt, | |
295 const uint32_t Sa) | |
296 { | |
297 IValueT Opcode = 0x00000003; | |
298 emitRdRtSa (Opcode, OpRd, OpRt, Sa, "sra"); | |
299 } | |
300 | |
301 void AssemblerMIPS32::addu(const Operand *OpRd, const Operand *OpRs, | |
302 const Operand *OpRt) | |
303 { | |
304 IValueT Opcode = 0x00000021; | |
305 emitRdRsRt (Opcode, OpRd, OpRs, OpRt, "addu"); | |
306 } | |
307 | |
308 void AssemblerMIPS32::slt(const Operand *OpRd, const Operand *OpRs, | |
309 const Operand *OpRt) | |
310 { | |
311 IValueT Opcode = 0x0000002A; | |
312 emitRdRsRt (Opcode, OpRd, OpRs, OpRt, "slt"); | |
313 } | |
314 | |
315 void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase, | |
316 const uint32_t Offset) | |
317 { | |
318 IValueT Opcode = 0xAC000000; | |
319 emitRtRsImm16 (Opcode, OpRt, OpBase, Offset, "sw"); | |
320 } | |
321 | |
322 void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase, | |
323 const uint32_t Offset) | |
324 { | |
325 IValueT Opcode = 0x8C000000; | |
326 emitRtRsImm16 (Opcode, OpRt, OpBase, Offset, "lw"); | |
327 } | |
328 | |
329 void AssemblerMIPS32::ret(void) | |
330 { | |
331 IValueT Opcode = 0x03E00008; // JR $31 | |
332 emitInst(Opcode); | |
333 nop(); // delay slot | |
334 } | |
335 | |
336 void AssemblerMIPS32::emitBr(const CondMIPS32::Cond Cond, | |
337 const Operand *OpRs, const Operand *OpRt, | |
338 IOffsetT Offset) | |
339 { | |
340 IValueT Opcode = 0; | |
341 | |
342 switch (Cond) { | |
343 default: | |
344 break; | |
Jim Stichnoth
2016/08/19 17:12:21
Is Opcode==0 ever valid here? If not, to be safe,
| |
345 case CondMIPS32::AL: | |
346 case CondMIPS32::EQ: | |
347 case CondMIPS32::EQZ: | |
348 Opcode = 0x10000000; | |
349 break; | |
350 case CondMIPS32::NE: | |
351 case CondMIPS32::NEZ: | |
352 Opcode = 0x14000000; | |
353 break; | |
354 case CondMIPS32::LEZ: | |
355 Opcode = 0x18000000; | |
356 break; | |
357 case CondMIPS32::LTZ: | |
358 Opcode = 0x04000000; | |
359 break; | |
360 case CondMIPS32::GEZ: | |
361 Opcode = 0x04010000; | |
362 break; | |
363 case CondMIPS32::GTZ: | |
364 Opcode = 0x1C000000; | |
365 break; | |
366 } | |
367 | |
368 if (OpRs != nullptr) { | |
369 IValueT Rs = encodeGPRegister(OpRs, "Rs", "branch"); | |
370 Opcode |= Rs << 21; | |
371 } | |
372 | |
373 if (OpRt != nullptr) { | |
374 IValueT Rt = encodeGPRegister(OpRt, "Rt", "branch"); | |
375 Opcode |= Rt << 16; | |
376 } | |
377 | |
378 Opcode = encodeBranchOffset(Offset, Opcode); | |
379 emitInst(Opcode); | |
380 nop(); // delay slot | |
381 } | |
382 | |
383 void AssemblerMIPS32::b(Label *TargetLabel) | |
384 { | |
385 if (TargetLabel->isBound()) { | |
386 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | |
387 emitBr(CondMIPS32::AL, nullptr, nullptr, Dest); | |
Jim Stichnoth
2016/08/19 17:12:20
I think it would be easier to read like this:
sta
| |
388 return; | |
389 } | |
390 const IOffsetT Position = Buffer.size(); | |
391 emitBr(CondMIPS32::AL, nullptr, nullptr, TargetLabel->getEncodedPosition()); | |
392 TargetLabel->linkTo(*this, Position); | |
393 } | |
394 | |
395 void AssemblerMIPS32::bcc(const CondMIPS32::Cond Cond, const Operand *OpRs, | |
396 const Operand *OpRt, Label *TargetLabel) | |
397 { | |
398 if (TargetLabel->isBound()) { | |
399 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | |
400 emitBr(Cond, OpRs, OpRt, Dest); | |
401 return; | |
402 } | |
403 const IOffsetT Position = Buffer.size(); | |
404 emitBr(Cond, OpRs, OpRt, TargetLabel->getEncodedPosition()); | |
405 TargetLabel->linkTo(*this, Position); | |
406 } | |
407 | |
408 void AssemblerMIPS32::bzc(const CondMIPS32::Cond Cond, const Operand *OpRs, | |
409 Label *TargetLabel) | |
410 { | |
411 if (TargetLabel->isBound()) { | |
412 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | |
413 emitBr(Cond, OpRs, nullptr, Dest); | |
414 return; | |
415 } | |
416 const IOffsetT Position = Buffer.size(); | |
417 emitBr(Cond, OpRs, nullptr, TargetLabel->getEncodedPosition()); | |
418 TargetLabel->linkTo(*this, Position); | |
419 } | |
420 | |
421 } // end of namespace MIPS32 | |
422 } // end of namespace Ice | |
423 | |
Jim Stichnoth
2016/08/19 17:12:21
remove trailing whitespace (blank line) to keep gi
| |
OLD | NEW |