| OLD | NEW |
| 1 //===- subzero/src/IceAssemblerMIPS32.cpp - MIPS32 Assembler --------------===// | 1 //===- subzero/src/IceAssemblerMIPS32.cpp - MIPS32 Assembler --------------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) { | 95 if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) { |
| 96 constexpr SizeT InstSize = 0; | 96 constexpr SizeT InstSize = 0; |
| 97 emitTextInst(Node->getAsmName() + ":", InstSize); | 97 emitTextInst(Node->getAsmName() + ":", InstSize); |
| 98 } | 98 } |
| 99 SizeT NodeNumber = Node->getIndex(); | 99 SizeT NodeNumber = Node->getIndex(); |
| 100 assert(!getPreliminary()); | 100 assert(!getPreliminary()); |
| 101 Label *L = getOrCreateCfgNodeLabel(NodeNumber); | 101 Label *L = getOrCreateCfgNodeLabel(NodeNumber); |
| 102 this->bind(L); | 102 this->bind(L); |
| 103 } | 103 } |
| 104 | 104 |
| 105 namespace { |
| 106 |
| 105 // Checks that Offset can fit in imm16 constant of branch instruction. | 107 // Checks that Offset can fit in imm16 constant of branch instruction. |
| 106 void assertCanEncodeBranchOffset(IOffsetT Offset) { | 108 void assertCanEncodeBranchOffset(IOffsetT Offset) { |
| 107 (void)Offset; | 109 (void)Offset; |
| 108 (void)kBranchOffsetBits; | 110 (void)kBranchOffsetBits; |
| 109 assert(Utils::IsAligned(Offset, 4)); | 111 assert(Utils::IsAligned(Offset, 4)); |
| 110 assert(Utils::IsInt(kBranchOffsetBits, Offset >> 2)); | 112 assert(Utils::IsInt(kBranchOffsetBits, Offset >> 2)); |
| 111 } | 113 } |
| 112 | 114 |
| 113 IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) { | 115 IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) { |
| 114 Offset -= kPCReadOffset; | 116 Offset -= kPCReadOffset; |
| 115 assertCanEncodeBranchOffset(Offset); | 117 assertCanEncodeBranchOffset(Offset); |
| 116 Offset >>= 2; | 118 Offset >>= 2; |
| 117 Offset &= kBranchOffsetMask; | 119 Offset &= kBranchOffsetMask; |
| 118 return (Inst & ~kBranchOffsetMask) | Offset; | 120 return (Inst & ~kBranchOffsetMask) | Offset; |
| 119 } | 121 } |
| 120 | 122 |
| 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 }; | 123 enum RegSetWanted { WantGPRegs, WantFPRegs }; |
| 142 | 124 |
| 143 IValueT getEncodedGPRegNum(const Variable *Var) { | 125 IValueT getEncodedGPRegNum(const Variable *Var) { |
| 144 assert(Var->hasReg()); | 126 assert(Var->hasReg() && isScalarIntegerType(Var->getType())); |
| 145 const auto Reg = Var->getRegNum(); | 127 const auto Reg = Var->getRegNum(); |
| 146 return RegMIPS32::getEncodedGPR(Reg); | 128 return RegMIPS32::getEncodedGPR(Reg); |
| 147 } | 129 } |
| 148 | 130 |
| 131 IValueT getEncodedFPRegNum(const Variable *Var) { |
| 132 assert(Var->hasReg() && isScalarFloatingType(Var->getType())); |
| 133 const auto Reg = Var->getRegNum(); |
| 134 IValueT RegEncoding; |
| 135 if (RegMIPS32::isFPRReg(Reg)) { |
| 136 RegEncoding = RegMIPS32::getEncodedFPR(Reg); |
| 137 } else { |
| 138 RegEncoding = RegMIPS32::getEncodedFPR64(Reg); |
| 139 } |
| 140 return RegEncoding; |
| 141 } |
| 142 |
| 149 bool encodeOperand(const Operand *Opnd, IValueT &Value, | 143 bool encodeOperand(const Operand *Opnd, IValueT &Value, |
| 150 RegSetWanted WantedRegSet) { | 144 RegSetWanted WantedRegSet) { |
| 151 Value = 0; | 145 Value = 0; |
| 152 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 146 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| 153 if (Var->hasReg()) { | 147 if (Var->hasReg()) { |
| 154 switch (WantedRegSet) { | 148 switch (WantedRegSet) { |
| 155 case WantGPRegs: | 149 case WantGPRegs: |
| 156 Value = getEncodedGPRegNum(Var); | 150 Value = getEncodedGPRegNum(Var); |
| 157 break; | 151 break; |
| 158 default: | 152 case WantFPRegs: |
| 153 Value = getEncodedFPRegNum(Var); |
| 159 break; | 154 break; |
| 160 } | 155 } |
| 161 return true; | 156 return true; |
| 162 } | 157 } |
| 163 return false; | 158 return false; |
| 164 } | 159 } |
| 165 return false; | 160 return false; |
| 166 } | 161 } |
| 167 | 162 |
| 168 IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet, | 163 IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet, |
| 169 const char *RegName, const char *InstName) { | 164 const char *RegName, const char *InstName) { |
| 170 IValueT Reg = 0; | 165 IValueT Reg = 0; |
| 171 if (encodeOperand(OpReg, Reg, WantedRegSet) != true) | 166 if (encodeOperand(OpReg, Reg, WantedRegSet) != true) |
| 172 llvm::report_fatal_error(std::string(InstName) + ": Can't find register " + | 167 llvm::report_fatal_error(std::string(InstName) + ": Can't find register " + |
| 173 RegName); | 168 RegName); |
| 174 return Reg; | 169 return Reg; |
| 175 } | 170 } |
| 176 | 171 |
| 177 IValueT encodeGPRegister(const Operand *OpReg, const char *RegName, | 172 IValueT encodeGPRegister(const Operand *OpReg, const char *RegName, |
| 178 const char *InstName) { | 173 const char *InstName) { |
| 179 return encodeRegister(OpReg, WantGPRegs, RegName, InstName); | 174 return encodeRegister(OpReg, WantGPRegs, RegName, InstName); |
| 180 } | 175 } |
| 181 | 176 |
| 177 IValueT encodeFPRegister(const Operand *OpReg, const char *RegName, |
| 178 const char *InstName) { |
| 179 return encodeRegister(OpReg, WantFPRegs, RegName, InstName); |
| 180 } |
| 181 } |
| 182 |
| 183 IOffsetT AssemblerMIPS32::decodeBranchOffset(IValueT Inst) { |
| 184 int16_t imm = (Inst & kBranchOffsetMask); |
| 185 IOffsetT Offset = imm; |
| 186 Offset = Offset << 2; |
| 187 return (Offset + kPCReadOffset); |
| 188 } |
| 189 |
| 190 void AssemblerMIPS32::bind(Label *L) { |
| 191 IOffsetT BoundPc = Buffer.size(); |
| 192 assert(!L->isBound()); // Labels can only be bound once. |
| 193 while (L->isLinked()) { |
| 194 IOffsetT Position = L->getLinkPosition(); |
| 195 IOffsetT Dest = BoundPc - Position; |
| 196 IValueT Inst = Buffer.load<IValueT>(Position); |
| 197 Buffer.store<IValueT>(Position, encodeBranchOffset(Dest, Inst)); |
| 198 L->setPosition(decodeBranchOffset(Inst)); |
| 199 } |
| 200 L->bindTo(BoundPc); |
| 201 } |
| 202 |
| 182 void AssemblerMIPS32::emitRtRsImm16(IValueT Opcode, const Operand *OpRt, | 203 void AssemblerMIPS32::emitRtRsImm16(IValueT Opcode, const Operand *OpRt, |
| 183 const Operand *OpRs, const uint32_t Imm, | 204 const Operand *OpRs, const uint32_t Imm, |
| 184 const char *InsnName) { | 205 const char *InsnName) { |
| 185 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | 206 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); |
| 186 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); | 207 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); |
| 187 | 208 |
| 188 Opcode |= Rs << 21; | 209 Opcode |= Rs << 21; |
| 189 Opcode |= Rt << 16; | 210 Opcode |= Rt << 16; |
| 190 Opcode |= Imm & 0xffff; | 211 Opcode |= Imm & 0xffff; |
| 191 | 212 |
| 192 emitInst(Opcode); | 213 emitInst(Opcode); |
| 193 } | 214 } |
| 194 | 215 |
| 216 void AssemblerMIPS32::emitFtRsImm16(IValueT Opcode, const Operand *OpFt, |
| 217 const Operand *OpRs, const uint32_t Imm, |
| 218 const char *InsnName) { |
| 219 const IValueT Ft = encodeFPRegister(OpFt, "Ft", InsnName); |
| 220 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); |
| 221 |
| 222 Opcode |= Rs << 21; |
| 223 Opcode |= Ft << 16; |
| 224 Opcode |= Imm & 0xffff; |
| 225 |
| 226 emitInst(Opcode); |
| 227 } |
| 228 |
| 195 void AssemblerMIPS32::emitRdRtSa(IValueT Opcode, const Operand *OpRd, | 229 void AssemblerMIPS32::emitRdRtSa(IValueT Opcode, const Operand *OpRd, |
| 196 const Operand *OpRt, const uint32_t Sa, | 230 const Operand *OpRt, const uint32_t Sa, |
| 197 const char *InsnName) { | 231 const char *InsnName) { |
| 198 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); | 232 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); |
| 199 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | 233 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); |
| 200 | 234 |
| 201 Opcode |= Rt << 16; | 235 Opcode |= Rt << 16; |
| 202 Opcode |= Rd << 11; | 236 Opcode |= Rd << 11; |
| 203 Opcode |= (Sa & 0x1f) << 6; | 237 Opcode |= (Sa & 0x1f) << 6; |
| 204 | 238 |
| 205 emitInst(Opcode); | 239 emitInst(Opcode); |
| 206 } | 240 } |
| 207 | 241 |
| 208 void AssemblerMIPS32::emitRdRsRt(IValueT Opcode, const Operand *OpRd, | 242 void AssemblerMIPS32::emitRdRsRt(IValueT Opcode, const Operand *OpRd, |
| 209 const Operand *OpRs, const Operand *OpRt, | 243 const Operand *OpRs, const Operand *OpRt, |
| 210 const char *InsnName) { | 244 const char *InsnName) { |
| 211 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); | 245 const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName); |
| 212 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); | 246 const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName); |
| 213 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); | 247 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); |
| 214 | 248 |
| 215 Opcode |= Rs << 21; | 249 Opcode |= Rs << 21; |
| 216 Opcode |= Rt << 16; | 250 Opcode |= Rt << 16; |
| 217 Opcode |= Rd << 11; | 251 Opcode |= Rd << 11; |
| 218 | 252 |
| 219 emitInst(Opcode); | 253 emitInst(Opcode); |
| 220 } | 254 } |
| 221 | 255 |
| 256 void AssemblerMIPS32::emitCOP1FmtFsFd(IValueT Opcode, FPInstDataFormat Format, |
| 257 const Operand *OpFd, const Operand *OpFs, |
| 258 const char *InsnName) { |
| 259 const IValueT Fd = encodeFPRegister(OpFd, "Fd", InsnName); |
| 260 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName); |
| 261 |
| 262 Opcode |= Fd << 6; |
| 263 Opcode |= Fs << 11; |
| 264 Opcode |= Format << 21; |
| 265 |
| 266 emitInst(Opcode); |
| 267 } |
| 268 |
| 269 void AssemblerMIPS32::emitCOP1FmtFtFsFd(IValueT Opcode, FPInstDataFormat Format, |
| 270 const Operand *OpFd, |
| 271 const Operand *OpFs, |
| 272 const Operand *OpFt, |
| 273 const char *InsnName) { |
| 274 const IValueT Fd = encodeFPRegister(OpFd, "Fd", InsnName); |
| 275 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName); |
| 276 const IValueT Ft = encodeFPRegister(OpFt, "Ft", InsnName); |
| 277 |
| 278 Opcode |= Fd << 6; |
| 279 Opcode |= Fs << 11; |
| 280 Opcode |= Ft << 16; |
| 281 Opcode |= Format << 21; |
| 282 |
| 283 emitInst(Opcode); |
| 284 } |
| 285 |
| 286 void AssemblerMIPS32::emitCOP1FmtRtFsFd(IValueT Opcode, FPInstDataFormat Format, |
| 287 const Operand *OpFd, |
| 288 const Operand *OpFs, |
| 289 const Operand *OpRt, |
| 290 const char *InsnName) { |
| 291 const IValueT Fd = encodeFPRegister(OpFd, "Fd", InsnName); |
| 292 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName); |
| 293 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); |
| 294 |
| 295 Opcode |= Fd << 6; |
| 296 Opcode |= Fs << 11; |
| 297 Opcode |= Rt << 16; |
| 298 Opcode |= Format << 21; |
| 299 |
| 300 emitInst(Opcode); |
| 301 } |
| 302 |
| 303 void AssemblerMIPS32::emitCOP1MovRtFs(IValueT Opcode, const Operand *OpRt, |
| 304 const Operand *OpFs, |
| 305 const char *InsnName) { |
| 306 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName); |
| 307 const IValueT Fs = encodeFPRegister(OpFs, "Fs", InsnName); |
| 308 Opcode |= Fs << 11; |
| 309 Opcode |= Rt << 16; |
| 310 |
| 311 emitInst(Opcode); |
| 312 } |
| 313 |
| 314 void AssemblerMIPS32::abs_d(const Operand *OpFd, const Operand *OpFs) { |
| 315 static constexpr IValueT Opcode = 0x44000005; |
| 316 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "abs.d"); |
| 317 } |
| 318 |
| 319 void AssemblerMIPS32::abs_s(const Operand *OpFd, const Operand *OpFs) { |
| 320 static constexpr IValueT Opcode = 0x44000005; |
| 321 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "abs.s"); |
| 322 } |
| 323 |
| 324 void AssemblerMIPS32::add_d(const Operand *OpFd, const Operand *OpFs, |
| 325 const Operand *OpFt) { |
| 326 static constexpr IValueT Opcode = 0x44000000; |
| 327 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "add.d"); |
| 328 } |
| 329 |
| 330 void AssemblerMIPS32::add_s(const Operand *OpFd, const Operand *OpFs, |
| 331 const Operand *OpFt) { |
| 332 static constexpr IValueT Opcode = 0x44000000; |
| 333 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "add.s"); |
| 334 } |
| 335 |
| 222 void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs, | 336 void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs, |
| 223 const uint32_t Imm) { | 337 const uint32_t Imm) { |
| 224 static constexpr IValueT Opcode = 0x24000000; | 338 static constexpr IValueT Opcode = 0x24000000; |
| 225 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "addiu"); | 339 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "addiu"); |
| 226 } | 340 } |
| 227 | 341 |
| 228 void AssemblerMIPS32::slti(const Operand *OpRt, const Operand *OpRs, | 342 void AssemblerMIPS32::addu(const Operand *OpRd, const Operand *OpRs, |
| 229 const uint32_t Imm) { | 343 const Operand *OpRt) { |
| 230 static constexpr IValueT Opcode = 0x28000000; | 344 static constexpr IValueT Opcode = 0x00000021; |
| 231 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "slti"); | 345 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "addu"); |
| 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 } | 346 } |
| 239 | 347 |
| 240 void AssemblerMIPS32::and_(const Operand *OpRd, const Operand *OpRs, | 348 void AssemblerMIPS32::and_(const Operand *OpRd, const Operand *OpRs, |
| 241 const Operand *OpRt) { | 349 const Operand *OpRt) { |
| 242 static constexpr IValueT Opcode = 0x00000024; | 350 static constexpr IValueT Opcode = 0x00000024; |
| 243 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "and"); | 351 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "and"); |
| 244 } | 352 } |
| 245 | 353 |
| 246 void AssemblerMIPS32::andi(const Operand *OpRt, const Operand *OpRs, | 354 void AssemblerMIPS32::andi(const Operand *OpRt, const Operand *OpRs, |
| 247 const uint32_t Imm) { | 355 const uint32_t Imm) { |
| 248 static constexpr IValueT Opcode = 0x30000000; | 356 static constexpr IValueT Opcode = 0x30000000; |
| 249 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "andi"); | 357 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "andi"); |
| 250 } | 358 } |
| 251 | 359 |
| 360 void AssemblerMIPS32::b(Label *TargetLabel) { |
| 361 static constexpr Operand *OpRsNone = nullptr; |
| 362 static constexpr Operand *OpRtNone = nullptr; |
| 363 if (TargetLabel->isBound()) { |
| 364 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); |
| 365 emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, Dest); |
| 366 return; |
| 367 } |
| 368 const IOffsetT Position = Buffer.size(); |
| 369 emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, TargetLabel->getEncodedPosition()); |
| 370 TargetLabel->linkTo(*this, Position); |
| 371 } |
| 372 |
| 373 void AssemblerMIPS32::cvt_d_l(const Operand *OpFd, const Operand *OpFs) { |
| 374 static constexpr IValueT Opcode = 0x44000021; |
| 375 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.d.l"); |
| 376 } |
| 377 |
| 378 void AssemblerMIPS32::cvt_d_s(const Operand *OpFd, const Operand *OpFs) { |
| 379 static constexpr IValueT Opcode = 0x44000021; |
| 380 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "cvt.d.s"); |
| 381 } |
| 382 |
| 383 void AssemblerMIPS32::cvt_d_w(const Operand *OpFd, const Operand *OpFs) { |
| 384 static constexpr IValueT Opcode = 0x44000021; |
| 385 emitCOP1FmtFsFd(Opcode, Word, OpFd, OpFs, "cvt.d.w"); |
| 386 } |
| 387 |
| 388 void AssemblerMIPS32::cvt_s_d(const Operand *OpFd, const Operand *OpFs) { |
| 389 static constexpr IValueT Opcode = 0x44000020; |
| 390 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "cvt.s.d"); |
| 391 } |
| 392 |
| 393 void AssemblerMIPS32::cvt_s_l(const Operand *OpFd, const Operand *OpFs) { |
| 394 static constexpr IValueT Opcode = 0x44000020; |
| 395 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.s.l"); |
| 396 } |
| 397 |
| 398 void AssemblerMIPS32::cvt_s_w(const Operand *OpFd, const Operand *OpFs) { |
| 399 static constexpr IValueT Opcode = 0x44000020; |
| 400 emitCOP1FmtFsFd(Opcode, Word, OpFd, OpFs, "cvt.s.w"); |
| 401 } |
| 402 |
| 403 void AssemblerMIPS32::div_d(const Operand *OpFd, const Operand *OpFs, |
| 404 const Operand *OpFt) { |
| 405 static constexpr IValueT Opcode = 0x44000003; |
| 406 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "div.d"); |
| 407 } |
| 408 |
| 409 void AssemblerMIPS32::div_s(const Operand *OpFd, const Operand *OpFs, |
| 410 const Operand *OpFt) { |
| 411 static constexpr IValueT Opcode = 0x44000003; |
| 412 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "div.s"); |
| 413 } |
| 414 |
| 415 void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase, |
| 416 const uint32_t Offset) { |
| 417 switch (OpRt->getType()) { |
| 418 case IceType_i1: |
| 419 case IceType_i8: { |
| 420 static constexpr IValueT Opcode = 0x80000000; |
| 421 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lb"); |
| 422 } |
| 423 case IceType_i16: { |
| 424 static constexpr IValueT Opcode = 0x84000000; |
| 425 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lh"); |
| 426 } |
| 427 case IceType_i32: { |
| 428 static constexpr IValueT Opcode = 0x8C000000; |
| 429 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lw"); |
| 430 break; |
| 431 } |
| 432 case IceType_f32: { |
| 433 static constexpr IValueT Opcode = 0xC4000000; |
| 434 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "lwc1"); |
| 435 } |
| 436 case IceType_f64: { |
| 437 static constexpr IValueT Opcode = 0xD4000000; |
| 438 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "ldc1"); |
| 439 break; |
| 440 } |
| 441 default: { UnimplementedError(getFlags()); } |
| 442 } |
| 443 } |
| 444 |
| 445 void AssemblerMIPS32::mfc1(const Operand *OpRt, const Operand *OpFs) { |
| 446 static constexpr IValueT Opcode = 0x44000000; |
| 447 emitCOP1MovRtFs(Opcode, OpRt, OpFs, "mfc1"); |
| 448 } |
| 449 |
| 450 void AssemblerMIPS32::mov_d(const Operand *OpFd, const Operand *OpFs) { |
| 451 static constexpr IValueT Opcode = 0x44000006; |
| 452 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "mov.d"); |
| 453 } |
| 454 |
| 455 void AssemblerMIPS32::mov_s(const Operand *OpFd, const Operand *OpFs) { |
| 456 static constexpr IValueT Opcode = 0x44000006; |
| 457 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "mov.s"); |
| 458 } |
| 459 |
| 460 void AssemblerMIPS32::move(const Operand *OpRd, const Operand *OpRs) { |
| 461 |
| 462 const Type DstType = OpRd->getType(); |
| 463 const Type SrcType = OpRs->getType(); |
| 464 |
| 465 if ((isScalarIntegerType(DstType) && isScalarFloatingType(SrcType)) || |
| 466 (isScalarFloatingType(DstType) && isScalarIntegerType(SrcType))) { |
| 467 if (isScalarFloatingType(DstType)) { |
| 468 mtc1(OpRd, OpRs); |
| 469 } else { |
| 470 mfc1(OpRd, OpRs); |
| 471 } |
| 472 } else { |
| 473 switch (DstType) { |
| 474 case IceType_f32: |
| 475 mov_s(OpRd, OpRs); |
| 476 break; |
| 477 case IceType_f64: |
| 478 mov_d(OpRd, OpRs); |
| 479 break; |
| 480 case IceType_i1: |
| 481 case IceType_i8: |
| 482 case IceType_i16: |
| 483 case IceType_i32: { |
| 484 IValueT Opcode = 0x00000021; |
| 485 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "pseudo-move"); |
| 486 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "pseudo-move"); |
| 487 const IValueT Rt = 0; // $0 |
| 488 Opcode |= Rs << 21; |
| 489 Opcode |= Rt << 16; |
| 490 Opcode |= Rd << 11; |
| 491 emitInst(Opcode); |
| 492 break; |
| 493 } |
| 494 default: { UnimplementedError(getFlags()); } |
| 495 } |
| 496 } |
| 497 } |
| 498 |
| 499 void AssemblerMIPS32::movn_d(const Operand *OpFd, const Operand *OpFs, |
| 500 const Operand *OpFt) { |
| 501 static constexpr IValueT Opcode = 0x44000013; |
| 502 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "movn.d"); |
| 503 } |
| 504 |
| 505 void AssemblerMIPS32::movn_s(const Operand *OpFd, const Operand *OpFs, |
| 506 const Operand *OpFt) { |
| 507 static constexpr IValueT Opcode = 0x44000013; |
| 508 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "movn.s"); |
| 509 } |
| 510 |
| 511 void AssemblerMIPS32::movz_d(const Operand *OpFd, const Operand *OpFs, |
| 512 const Operand *OpFt) { |
| 513 static constexpr IValueT Opcode = 0x44000012; |
| 514 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "movz.d"); |
| 515 } |
| 516 |
| 517 void AssemblerMIPS32::movz_s(const Operand *OpFd, const Operand *OpFs, |
| 518 const Operand *OpFt) { |
| 519 static constexpr IValueT Opcode = 0x44000012; |
| 520 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "movz.s"); |
| 521 } |
| 522 |
| 523 void AssemblerMIPS32::mtc1(const Operand *OpRt, const Operand *OpFs) { |
| 524 static constexpr IValueT Opcode = 0x44800000; |
| 525 emitCOP1MovRtFs(Opcode, OpRt, OpFs, "mtc1"); |
| 526 } |
| 527 |
| 528 void AssemblerMIPS32::mul_d(const Operand *OpFd, const Operand *OpFs, |
| 529 const Operand *OpFt) { |
| 530 static constexpr IValueT Opcode = 0x44000002; |
| 531 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "mul.d"); |
| 532 } |
| 533 |
| 534 void AssemblerMIPS32::mul_s(const Operand *OpFd, const Operand *OpFs, |
| 535 const Operand *OpFt) { |
| 536 static constexpr IValueT Opcode = 0x44000002; |
| 537 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "mul.s"); |
| 538 } |
| 539 |
| 252 void AssemblerMIPS32::or_(const Operand *OpRd, const Operand *OpRs, | 540 void AssemblerMIPS32::or_(const Operand *OpRd, const Operand *OpRs, |
| 253 const Operand *OpRt) { | 541 const Operand *OpRt) { |
| 254 static constexpr IValueT Opcode = 0x00000025; | 542 static constexpr IValueT Opcode = 0x00000025; |
| 255 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "or"); | 543 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "or"); |
| 256 } | 544 } |
| 257 | 545 |
| 258 void AssemblerMIPS32::ori(const Operand *OpRt, const Operand *OpRs, | 546 void AssemblerMIPS32::ori(const Operand *OpRt, const Operand *OpRs, |
| 259 const uint32_t Imm) { | 547 const uint32_t Imm) { |
| 260 static constexpr IValueT Opcode = 0x34000000; | 548 static constexpr IValueT Opcode = 0x34000000; |
| 261 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "ori"); | 549 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "ori"); |
| 262 } | 550 } |
| 263 | 551 |
| 264 void AssemblerMIPS32::xor_(const Operand *OpRd, const Operand *OpRs, | 552 void AssemblerMIPS32::ret(void) { |
| 265 const Operand *OpRt) { | 553 static constexpr IValueT Opcode = 0x03E00008; // JR $31 |
| 266 static constexpr IValueT Opcode = 0x00000026; | 554 emitInst(Opcode); |
| 267 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "xor"); | 555 nop(); // delay slot |
| 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 } | 556 } |
| 275 | 557 |
| 276 void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt, | 558 void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt, |
| 277 const uint32_t Sa) { | 559 const uint32_t Sa) { |
| 278 static constexpr IValueT Opcode = 0x00000000; | 560 static constexpr IValueT Opcode = 0x00000000; |
| 279 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sll"); | 561 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sll"); |
| 280 } | 562 } |
| 281 | 563 |
| 282 void AssemblerMIPS32::srl(const Operand *OpRd, const Operand *OpRt, | 564 void AssemblerMIPS32::slt(const Operand *OpRd, const Operand *OpRs, |
| 283 const uint32_t Sa) { | 565 const Operand *OpRt) { |
| 284 static constexpr IValueT Opcode = 0x00000002; | 566 static constexpr IValueT Opcode = 0x0000002A; |
| 285 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "srl"); | 567 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "slt"); |
| 568 } |
| 569 |
| 570 void AssemblerMIPS32::slti(const Operand *OpRt, const Operand *OpRs, |
| 571 const uint32_t Imm) { |
| 572 static constexpr IValueT Opcode = 0x28000000; |
| 573 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "slti"); |
| 574 } |
| 575 |
| 576 void AssemblerMIPS32::sltu(const Operand *OpRd, const Operand *OpRs, |
| 577 const Operand *OpRt) { |
| 578 static constexpr IValueT Opcode = 0x0000002B; |
| 579 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "sltu"); |
| 580 } |
| 581 |
| 582 void AssemblerMIPS32::sltiu(const Operand *OpRt, const Operand *OpRs, |
| 583 const uint32_t Imm) { |
| 584 static constexpr IValueT Opcode = 0x2c000000; |
| 585 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "sltiu"); |
| 586 } |
| 587 |
| 588 void AssemblerMIPS32::sqrt_d(const Operand *OpFd, const Operand *OpFs) { |
| 589 static constexpr IValueT Opcode = 0x44000004; |
| 590 emitCOP1FmtFsFd(Opcode, DoublePrecision, OpFd, OpFs, "sqrt.d"); |
| 591 } |
| 592 |
| 593 void AssemblerMIPS32::sqrt_s(const Operand *OpFd, const Operand *OpFs) { |
| 594 static constexpr IValueT Opcode = 0x44000004; |
| 595 emitCOP1FmtFsFd(Opcode, SinglePrecision, OpFd, OpFs, "sqrt.s"); |
| 286 } | 596 } |
| 287 | 597 |
| 288 void AssemblerMIPS32::sra(const Operand *OpRd, const Operand *OpRt, | 598 void AssemblerMIPS32::sra(const Operand *OpRd, const Operand *OpRt, |
| 289 const uint32_t Sa) { | 599 const uint32_t Sa) { |
| 290 static constexpr IValueT Opcode = 0x00000003; | 600 static constexpr IValueT Opcode = 0x00000003; |
| 291 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sra"); | 601 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sra"); |
| 292 } | 602 } |
| 293 | 603 |
| 294 void AssemblerMIPS32::move(const Operand *OpRd, const Operand *OpRs) { | 604 void AssemblerMIPS32::srl(const Operand *OpRd, const Operand *OpRt, |
| 295 IValueT Opcode = 0x00000021; | 605 const uint32_t Sa) { |
| 296 const IValueT Rd = encodeGPRegister(OpRd, "Rd", "pseudo-move"); | 606 static constexpr IValueT Opcode = 0x00000002; |
| 297 const IValueT Rs = encodeGPRegister(OpRs, "Rs", "pseudo-move"); | 607 emitRdRtSa(Opcode, OpRd, OpRt, Sa, "srl"); |
| 298 const IValueT Rt = 0; // $0 | |
| 299 Opcode |= Rs << 21; | |
| 300 Opcode |= Rt << 16; | |
| 301 Opcode |= Rd << 11; | |
| 302 emitInst(Opcode); | |
| 303 } | 608 } |
| 304 | 609 |
| 305 void AssemblerMIPS32::addu(const Operand *OpRd, const Operand *OpRs, | 610 void AssemblerMIPS32::sub_d(const Operand *OpFd, const Operand *OpFs, |
| 306 const Operand *OpRt) { | 611 const Operand *OpFt) { |
| 307 static constexpr IValueT Opcode = 0x00000021; | 612 static constexpr IValueT Opcode = 0x44000001; |
| 308 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "addu"); | 613 emitCOP1FmtFtFsFd(Opcode, DoublePrecision, OpFd, OpFs, OpFt, "sub.d"); |
| 309 } | 614 } |
| 310 | 615 |
| 311 void AssemblerMIPS32::sltu(const Operand *OpRd, const Operand *OpRs, | 616 void AssemblerMIPS32::sub_s(const Operand *OpFd, const Operand *OpFs, |
| 312 const Operand *OpRt) { | 617 const Operand *OpFt) { |
| 313 static constexpr IValueT Opcode = 0x0000002B; | 618 static constexpr IValueT Opcode = 0x44000001; |
| 314 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "sltu"); | 619 emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "sub.s"); |
| 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 } | 620 } |
| 322 | 621 |
| 323 void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase, | 622 void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase, |
| 324 const uint32_t Offset) { | 623 const uint32_t Offset) { |
| 325 static constexpr IValueT Opcode = 0xAC000000; | 624 switch (OpRt->getType()) { |
| 326 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sw"); | 625 case IceType_i1: |
| 626 case IceType_i8: { |
| 627 static constexpr IValueT Opcode = 0xA0000000; |
| 628 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sb"); |
| 629 break; |
| 630 } |
| 631 case IceType_i16: { |
| 632 static constexpr IValueT Opcode = 0xA4000000; |
| 633 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sh"); |
| 634 break; |
| 635 } |
| 636 case IceType_i32: { |
| 637 static constexpr IValueT Opcode = 0xAC000000; |
| 638 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sw"); |
| 639 break; |
| 640 } |
| 641 case IceType_f32: { |
| 642 static constexpr IValueT Opcode = 0xE4000000; |
| 643 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "swc1"); |
| 644 break; |
| 645 } |
| 646 case IceType_f64: { |
| 647 static constexpr IValueT Opcode = 0xF4000000; |
| 648 emitFtRsImm16(Opcode, OpRt, OpBase, Offset, "sdc1"); |
| 649 break; |
| 650 } |
| 651 default: { UnimplementedError(getFlags()); } |
| 652 } |
| 327 } | 653 } |
| 328 | 654 |
| 329 void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase, | 655 void AssemblerMIPS32::trunc_l_d(const Operand *OpFd, const Operand *OpFs) { |
| 330 const uint32_t Offset) { | 656 static constexpr IValueT Opcode = 0x4400000D; |
| 331 static constexpr IValueT Opcode = 0x8C000000; | 657 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "trunc.l.d"); |
| 332 emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lw"); | |
| 333 } | 658 } |
| 334 | 659 |
| 335 void AssemblerMIPS32::ret(void) { | 660 void AssemblerMIPS32::trunc_l_s(const Operand *OpFd, const Operand *OpFs) { |
| 336 static constexpr IValueT Opcode = 0x03E00008; // JR $31 | 661 static constexpr IValueT Opcode = 0x4400000D; |
| 337 emitInst(Opcode); | 662 emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "trunc.l.s"); |
| 338 nop(); // delay slot | 663 } |
| 664 |
| 665 void AssemblerMIPS32::trunc_w_d(const Operand *OpFd, const Operand *OpFs) { |
| 666 static constexpr IValueT Opcode = 0x4400000D; |
| 667 emitCOP1FmtFsFd(Opcode, Word, OpFd, OpFs, "trunc.w.d"); |
| 668 } |
| 669 |
| 670 void AssemblerMIPS32::trunc_w_s(const Operand *OpFd, const Operand *OpFs) { |
| 671 static constexpr IValueT Opcode = 0x4400000D; |
| 672 emitCOP1FmtFsFd(Opcode, Word, OpFd, OpFs, "trunc.w.s"); |
| 673 } |
| 674 |
| 675 void AssemblerMIPS32::xor_(const Operand *OpRd, const Operand *OpRs, |
| 676 const Operand *OpRt) { |
| 677 static constexpr IValueT Opcode = 0x00000026; |
| 678 emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "xor"); |
| 679 } |
| 680 |
| 681 void AssemblerMIPS32::xori(const Operand *OpRt, const Operand *OpRs, |
| 682 const uint32_t Imm) { |
| 683 static constexpr IValueT Opcode = 0x38000000; |
| 684 emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "xori"); |
| 339 } | 685 } |
| 340 | 686 |
| 341 void AssemblerMIPS32::emitBr(const CondMIPS32::Cond Cond, const Operand *OpRs, | 687 void AssemblerMIPS32::emitBr(const CondMIPS32::Cond Cond, const Operand *OpRs, |
| 342 const Operand *OpRt, IOffsetT Offset) { | 688 const Operand *OpRt, IOffsetT Offset) { |
| 343 IValueT Opcode = 0; | 689 IValueT Opcode = 0; |
| 344 | 690 |
| 345 switch (Cond) { | 691 switch (Cond) { |
| 346 default: | 692 default: |
| 347 break; | 693 break; |
| 348 case CondMIPS32::AL: | 694 case CondMIPS32::AL: |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 if (OpRt != nullptr) { | 726 if (OpRt != nullptr) { |
| 381 IValueT Rt = encodeGPRegister(OpRt, "Rt", "branch"); | 727 IValueT Rt = encodeGPRegister(OpRt, "Rt", "branch"); |
| 382 Opcode |= Rt << 16; | 728 Opcode |= Rt << 16; |
| 383 } | 729 } |
| 384 | 730 |
| 385 Opcode = encodeBranchOffset(Offset, Opcode); | 731 Opcode = encodeBranchOffset(Offset, Opcode); |
| 386 emitInst(Opcode); | 732 emitInst(Opcode); |
| 387 nop(); // delay slot | 733 nop(); // delay slot |
| 388 } | 734 } |
| 389 | 735 |
| 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, | 736 void AssemblerMIPS32::bcc(const CondMIPS32::Cond Cond, const Operand *OpRs, |
| 404 const Operand *OpRt, Label *TargetLabel) { | 737 const Operand *OpRt, Label *TargetLabel) { |
| 405 if (TargetLabel->isBound()) { | 738 if (TargetLabel->isBound()) { |
| 406 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | 739 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); |
| 407 emitBr(Cond, OpRs, OpRt, Dest); | 740 emitBr(Cond, OpRs, OpRt, Dest); |
| 408 return; | 741 return; |
| 409 } | 742 } |
| 410 const IOffsetT Position = Buffer.size(); | 743 const IOffsetT Position = Buffer.size(); |
| 411 emitBr(Cond, OpRs, OpRt, TargetLabel->getEncodedPosition()); | 744 emitBr(Cond, OpRs, OpRt, TargetLabel->getEncodedPosition()); |
| 412 TargetLabel->linkTo(*this, Position); | 745 TargetLabel->linkTo(*this, Position); |
| 413 } | 746 } |
| 414 | 747 |
| 415 void AssemblerMIPS32::bzc(const CondMIPS32::Cond Cond, const Operand *OpRs, | 748 void AssemblerMIPS32::bzc(const CondMIPS32::Cond Cond, const Operand *OpRs, |
| 416 Label *TargetLabel) { | 749 Label *TargetLabel) { |
| 417 static constexpr Operand *OpRtNone = nullptr; | 750 static constexpr Operand *OpRtNone = nullptr; |
| 418 if (TargetLabel->isBound()) { | 751 if (TargetLabel->isBound()) { |
| 419 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); | 752 const int32_t Dest = TargetLabel->getPosition() - Buffer.size(); |
| 420 emitBr(Cond, OpRs, OpRtNone, Dest); | 753 emitBr(Cond, OpRs, OpRtNone, Dest); |
| 421 return; | 754 return; |
| 422 } | 755 } |
| 423 const IOffsetT Position = Buffer.size(); | 756 const IOffsetT Position = Buffer.size(); |
| 424 emitBr(Cond, OpRs, OpRtNone, TargetLabel->getEncodedPosition()); | 757 emitBr(Cond, OpRs, OpRtNone, TargetLabel->getEncodedPosition()); |
| 425 TargetLabel->linkTo(*this, Position); | 758 TargetLabel->linkTo(*this, Position); |
| 426 } | 759 } |
| 427 | 760 |
| 428 } // end of namespace MIPS32 | 761 } // end of namespace MIPS32 |
| 429 } // end of namespace Ice | 762 } // end of namespace Ice |
| OLD | NEW |