OLD | NEW |
(Empty) | |
| 1 //===- 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 |
| 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 |