Chromium Code Reviews| 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 |