OLD | NEW |
1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// | 1 //===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===// |
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 // This file declares the InstARM32 and OperandARM32 classes and | 10 // This file declares the InstARM32 and OperandARM32 classes and |
(...skipping 227 matching lines...) Loading... |
238 }; | 238 }; |
239 | 239 |
240 class InstARM32 : public InstTarget { | 240 class InstARM32 : public InstTarget { |
241 InstARM32() = delete; | 241 InstARM32() = delete; |
242 InstARM32(const InstARM32 &) = delete; | 242 InstARM32(const InstARM32 &) = delete; |
243 InstARM32 &operator=(const InstARM32 &) = delete; | 243 InstARM32 &operator=(const InstARM32 &) = delete; |
244 | 244 |
245 public: | 245 public: |
246 enum InstKindARM32 { | 246 enum InstKindARM32 { |
247 k__Start = Inst::Target, | 247 k__Start = Inst::Target, |
| 248 Adc, |
| 249 Add, |
| 250 And, |
| 251 Eor, |
| 252 Ldr, |
| 253 Mla, |
248 Mov, | 254 Mov, |
249 Movt, | 255 Movt, |
250 Movw, | 256 Movw, |
| 257 Mul, |
251 Mvn, | 258 Mvn, |
| 259 Orr, |
252 Ret, | 260 Ret, |
253 Ldr | 261 Sbc, |
| 262 Sub, |
| 263 Umull |
254 }; | 264 }; |
255 | 265 |
256 static const char *getWidthString(Type Ty); | 266 static const char *getWidthString(Type Ty); |
257 | 267 |
258 void dump(const Cfg *Func) const override; | 268 void dump(const Cfg *Func) const override; |
259 | 269 |
260 protected: | 270 protected: |
261 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) | 271 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) |
262 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} | 272 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} |
263 ~InstARM32() override {} | 273 ~InstARM32() override {} |
264 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { | 274 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { |
265 return Inst->getKind() == static_cast<InstKind>(MyKind); | 275 return Inst->getKind() == static_cast<InstKind>(MyKind); |
266 } | 276 } |
267 }; | 277 }; |
268 | 278 |
269 void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func); | 279 void emitTwoAddr(const char *Opcode, const Inst *Inst, const Cfg *Func); |
| 280 void emitThreeAddr(const char *Opcode, const Inst *Inst, const Cfg *Func, |
| 281 bool SetFlags); |
270 | 282 |
271 // TODO(jvoung): add condition codes if instruction can be predicated. | 283 // TODO(jvoung): add condition codes if instruction can be predicated. |
272 | 284 |
273 // Instructions of the form x := op(y). | 285 // Instructions of the form x := op(y). |
274 template <InstARM32::InstKindARM32 K> | 286 template <InstARM32::InstKindARM32 K> |
275 class InstARM32UnaryopGPR : public InstARM32 { | 287 class InstARM32UnaryopGPR : public InstARM32 { |
276 InstARM32UnaryopGPR() = delete; | 288 InstARM32UnaryopGPR() = delete; |
277 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; | 289 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete; |
278 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; | 290 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete; |
279 | 291 |
(...skipping 110 matching lines...) Loading... |
390 private: | 402 private: |
391 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source) | 403 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source) |
392 : InstARM32(Func, K, 1, Dest) { | 404 : InstARM32(Func, K, 1, Dest) { |
393 addSource(Source); | 405 addSource(Source); |
394 } | 406 } |
395 ~InstARM32Movlike() override {} | 407 ~InstARM32Movlike() override {} |
396 | 408 |
397 static const char *Opcode; | 409 static const char *Opcode; |
398 }; | 410 }; |
399 | 411 |
| 412 // Instructions of the form x := y op z. May have the side-effect of setting |
| 413 // status flags. |
| 414 template <InstARM32::InstKindARM32 K> |
| 415 class InstARM32ThreeAddrGPR : public InstARM32 { |
| 416 InstARM32ThreeAddrGPR() = delete; |
| 417 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete; |
| 418 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete; |
| 419 |
| 420 public: |
| 421 // Create an ordinary binary-op instruction like add, and sub. |
| 422 // Dest and Src1 must be registers. |
| 423 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest, |
| 424 Variable *Src1, Operand *Src2, |
| 425 bool SetFlags = false) { |
| 426 return new (Func->allocate<InstARM32ThreeAddrGPR>()) |
| 427 InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, SetFlags); |
| 428 } |
| 429 void emit(const Cfg *Func) const override { |
| 430 if (!ALLOW_DUMP) |
| 431 return; |
| 432 emitThreeAddr(Opcode, this, Func, SetFlags); |
| 433 } |
| 434 void emitIAS(const Cfg *Func) const override { |
| 435 (void)Func; |
| 436 llvm::report_fatal_error("Not yet implemented"); |
| 437 } |
| 438 void dump(const Cfg *Func) const override { |
| 439 if (!ALLOW_DUMP) |
| 440 return; |
| 441 Ostream &Str = Func->getContext()->getStrDump(); |
| 442 dumpDest(Func); |
| 443 Str << " = " << Opcode << (SetFlags ? "s" : "") << "." |
| 444 << getDest()->getType() << " "; |
| 445 dumpSources(Func); |
| 446 } |
| 447 static bool classof(const Inst *Inst) { return isClassof(Inst, K); } |
| 448 |
| 449 private: |
| 450 InstARM32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src1, |
| 451 Operand *Src2, bool SetFlags) |
| 452 : InstARM32(Func, K, 2, Dest), SetFlags(SetFlags) { |
| 453 addSource(Src1); |
| 454 addSource(Src2); |
| 455 } |
| 456 ~InstARM32ThreeAddrGPR() override {} |
| 457 static const char *Opcode; |
| 458 bool SetFlags; |
| 459 }; |
| 460 |
| 461 typedef InstARM32ThreeAddrGPR<InstARM32::Adc> InstARM32Adc; |
| 462 typedef InstARM32ThreeAddrGPR<InstARM32::Add> InstARM32Add; |
| 463 typedef InstARM32ThreeAddrGPR<InstARM32::And> InstARM32And; |
| 464 typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor; |
| 465 typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul; |
| 466 typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr; |
| 467 typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc; |
| 468 typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub; |
400 // Move instruction (variable <- flex). This is more of a pseudo-inst. | 469 // Move instruction (variable <- flex). This is more of a pseudo-inst. |
401 // If var is a register, then we use "mov". If var is stack, then we use | 470 // If var is a register, then we use "mov". If var is stack, then we use |
402 // "str" to store to the stack. | 471 // "str" to store to the stack. |
403 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; | 472 typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov; |
404 // MovT leaves the bottom bits alone so dest is also a source. | 473 // MovT leaves the bottom bits alone so dest is also a source. |
405 // This helps indicate that a previous MovW setting dest is not dead code. | 474 // This helps indicate that a previous MovW setting dest is not dead code. |
406 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; | 475 typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt; |
407 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; | 476 typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw; |
408 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; | 477 typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn; |
409 | 478 |
(...skipping 11 matching lines...) Loading... |
421 void emit(const Cfg *Func) const override; | 490 void emit(const Cfg *Func) const override; |
422 void emitIAS(const Cfg *Func) const override; | 491 void emitIAS(const Cfg *Func) const override; |
423 void dump(const Cfg *Func) const override; | 492 void dump(const Cfg *Func) const override; |
424 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } | 493 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); } |
425 | 494 |
426 private: | 495 private: |
427 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem); | 496 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem); |
428 ~InstARM32Ldr() override {} | 497 ~InstARM32Ldr() override {} |
429 }; | 498 }; |
430 | 499 |
| 500 // Multiply Accumulate: d := x * y + a |
| 501 class InstARM32Mla : public InstARM32 { |
| 502 InstARM32Mla() = delete; |
| 503 InstARM32Mla(const InstARM32Mla &) = delete; |
| 504 InstARM32Mla &operator=(const InstARM32Mla &) = delete; |
| 505 |
| 506 public: |
| 507 // Everything must be a register. |
| 508 static InstARM32Mla *create(Cfg *Func, Variable *Dest, Variable *Src0, |
| 509 Variable *Src1, Variable *Acc) { |
| 510 return new (Func->allocate<InstARM32Mla>()) |
| 511 InstARM32Mla(Func, Dest, Src0, Src1, Acc); |
| 512 } |
| 513 void emit(const Cfg *Func) const override; |
| 514 void emitIAS(const Cfg *Func) const override; |
| 515 void dump(const Cfg *Func) const override; |
| 516 static bool classof(const Inst *Inst) { return isClassof(Inst, Mla); } |
| 517 |
| 518 private: |
| 519 InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1, |
| 520 Variable *Acc); |
| 521 ~InstARM32Mla() override {} |
| 522 }; |
| 523 |
431 // Ret pseudo-instruction. This is actually a "bx" instruction with | 524 // Ret pseudo-instruction. This is actually a "bx" instruction with |
432 // an "lr" register operand, but epilogue lowering will search for a Ret | 525 // an "lr" register operand, but epilogue lowering will search for a Ret |
433 // instead of a generic "bx". This instruction also takes a Source | 526 // instead of a generic "bx". This instruction also takes a Source |
434 // operand (for non-void returning functions) for liveness analysis, though | 527 // operand (for non-void returning functions) for liveness analysis, though |
435 // a FakeUse before the ret would do just as well. | 528 // a FakeUse before the ret would do just as well. |
436 class InstARM32Ret : public InstARM32 { | 529 class InstARM32Ret : public InstARM32 { |
437 InstARM32Ret() = delete; | 530 InstARM32Ret() = delete; |
438 InstARM32Ret(const InstARM32Ret &) = delete; | 531 InstARM32Ret(const InstARM32Ret &) = delete; |
439 InstARM32Ret &operator=(const InstARM32Ret &) = delete; | 532 InstARM32Ret &operator=(const InstARM32Ret &) = delete; |
440 | 533 |
441 public: | 534 public: |
442 static InstARM32Ret *create(Cfg *Func, Variable *LR, | 535 static InstARM32Ret *create(Cfg *Func, Variable *LR, |
443 Variable *Source = nullptr) { | 536 Variable *Source = nullptr) { |
444 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); | 537 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source); |
445 } | 538 } |
446 void emit(const Cfg *Func) const override; | 539 void emit(const Cfg *Func) const override; |
447 void emitIAS(const Cfg *Func) const override; | 540 void emitIAS(const Cfg *Func) const override; |
448 void dump(const Cfg *Func) const override; | 541 void dump(const Cfg *Func) const override; |
449 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } | 542 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); } |
450 | 543 |
451 private: | 544 private: |
452 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); | 545 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source); |
453 ~InstARM32Ret() override {} | 546 ~InstARM32Ret() override {} |
454 }; | 547 }; |
455 | 548 |
| 549 // Unsigned Multiply Long: d.lo, d.hi := x * y |
| 550 class InstARM32Umull : public InstARM32 { |
| 551 InstARM32Umull() = delete; |
| 552 InstARM32Umull(const InstARM32Umull &) = delete; |
| 553 InstARM32Umull &operator=(const InstARM32Umull &) = delete; |
| 554 |
| 555 public: |
| 556 // Everything must be a register. |
| 557 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi, |
| 558 Variable *Src0, Variable *Src1) { |
| 559 return new (Func->allocate<InstARM32Umull>()) |
| 560 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1); |
| 561 } |
| 562 void emit(const Cfg *Func) const override; |
| 563 void emitIAS(const Cfg *Func) const override; |
| 564 void dump(const Cfg *Func) const override; |
| 565 static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); } |
| 566 |
| 567 private: |
| 568 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0, |
| 569 Variable *Src1); |
| 570 ~InstARM32Umull() override {} |
| 571 Variable *DestHi; |
| 572 }; |
| 573 |
456 // Declare partial template specializations of emit() methods that | 574 // Declare partial template specializations of emit() methods that |
457 // already have default implementations. Without this, there is the | 575 // already have default implementations. Without this, there is the |
458 // possibility of ODR violations and link errors. | 576 // possibility of ODR violations and link errors. |
459 | 577 |
460 template <> void InstARM32Movw::emit(const Cfg *Func) const; | 578 template <> void InstARM32Movw::emit(const Cfg *Func) const; |
461 template <> void InstARM32Movt::emit(const Cfg *Func) const; | 579 template <> void InstARM32Movt::emit(const Cfg *Func) const; |
462 | 580 |
463 } // end of namespace Ice | 581 } // end of namespace Ice |
464 | 582 |
465 #endif // SUBZERO_SRC_ICEINSTARM32_H | 583 #endif // SUBZERO_SRC_ICEINSTARM32_H |
OLD | NEW |