Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(714)

Side by Side Diff: src/IceAssemblerMIPS32.cpp

Issue 2259983004: [SubZero] Generate ELF output for MIPS (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW
« src/IceAssemblerMIPS32.h ('K') | « src/IceAssemblerMIPS32.h ('k') | src/IceInstMIPS32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698