OLD | NEW |
1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===// | 1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===// |
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 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 addSource(Src1); | 375 addSource(Src1); |
376 } | 376 } |
377 | 377 |
378 InstARM32Vcvt::InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, | 378 InstARM32Vcvt::InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, |
379 VcvtVariant Variant, CondARM32::Cond Predicate) | 379 VcvtVariant Variant, CondARM32::Cond Predicate) |
380 : InstARM32Pred(Func, InstARM32::Vcvt, 1, Dest, Predicate), | 380 : InstARM32Pred(Func, InstARM32::Vcvt, 1, Dest, Predicate), |
381 Variant(Variant) { | 381 Variant(Variant) { |
382 addSource(Src); | 382 addSource(Src); |
383 } | 383 } |
384 | 384 |
| 385 InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Variable *Src1, |
| 386 CondARM32::Cond Predicate) |
| 387 : InstARM32Pred(Func, InstARM32::Vcmp, 2, nullptr, Predicate) { |
| 388 addSource(Src0); |
| 389 addSource(Src1); |
| 390 } |
| 391 |
| 392 InstARM32Vmrs::InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate) |
| 393 : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) {} |
| 394 |
385 // ======================== Dump routines ======================== // | 395 // ======================== Dump routines ======================== // |
386 | 396 |
387 // Two-addr ops | 397 // Two-addr ops |
388 template <> const char *InstARM32Movt::Opcode = "movt"; | 398 template <> const char *InstARM32Movt::Opcode = "movt"; |
389 // Unary ops | 399 // Unary ops |
390 template <> const char *InstARM32Movw::Opcode = "movw"; | 400 template <> const char *InstARM32Movw::Opcode = "movw"; |
391 template <> const char *InstARM32Clz::Opcode = "clz"; | 401 template <> const char *InstARM32Clz::Opcode = "clz"; |
392 template <> const char *InstARM32Mvn::Opcode = "mvn"; | 402 template <> const char *InstARM32Mvn::Opcode = "mvn"; |
393 template <> const char *InstARM32Rbit::Opcode = "rbit"; | 403 template <> const char *InstARM32Rbit::Opcode = "rbit"; |
394 template <> const char *InstARM32Rev::Opcode = "rev"; | 404 template <> const char *InstARM32Rev::Opcode = "rev"; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 return; | 510 return; |
501 Ostream &Str = Func->getContext()->getStrEmit(); | 511 Ostream &Str = Func->getContext()->getStrEmit(); |
502 Variable *Dest0 = getDest(); | 512 Variable *Dest0 = getDest(); |
503 Operand *Src0 = getSrc(0); | 513 Operand *Src0 = getSrc(0); |
504 | 514 |
505 assert(Dest0->hasReg()); | 515 assert(Dest0->hasReg()); |
506 assert(Dest1->hasReg()); | 516 assert(Dest1->hasReg()); |
507 assert(!llvm::isa<OperandARM32Mem>(Src0)); | 517 assert(!llvm::isa<OperandARM32Mem>(Src0)); |
508 | 518 |
509 Str << "\t" | 519 Str << "\t" |
510 << "vmov" | 520 << "vmov" << getPredicate() << "\t"; |
511 << "\t"; | |
512 Dest0->emit(Func); | 521 Dest0->emit(Func); |
513 Str << ", "; | 522 Str << ", "; |
514 Dest1->emit(Func); | 523 Dest1->emit(Func); |
515 Str << ", "; | 524 Str << ", "; |
516 Src0->emit(Func); | 525 Src0->emit(Func); |
517 } | 526 } |
518 | 527 |
519 void InstARM32Vmov::emitSingleDestMultiSource(const Cfg *Func) const { | 528 void InstARM32Vmov::emitSingleDestMultiSource(const Cfg *Func) const { |
520 if (!BuildDefs::dump()) | 529 if (!BuildDefs::dump()) |
521 return; | 530 return; |
522 Ostream &Str = Func->getContext()->getStrEmit(); | 531 Ostream &Str = Func->getContext()->getStrEmit(); |
523 Variable *Dest0 = getDest(); | 532 Variable *Dest0 = getDest(); |
524 Operand *Src0 = getSrc(0); | 533 Operand *Src0 = getSrc(0); |
525 Operand *Src1 = getSrc(1); | 534 Operand *Src1 = getSrc(1); |
526 | 535 |
527 assert(Dest0->hasReg()); | 536 assert(Dest0->hasReg()); |
528 assert(!llvm::isa<OperandARM32Mem>(Src0)); | 537 assert(!llvm::isa<OperandARM32Mem>(Src0)); |
529 assert(!llvm::isa<OperandARM32Mem>(Src1)); | 538 assert(!llvm::isa<OperandARM32Mem>(Src1)); |
530 | 539 |
531 Str << "\t" | 540 Str << "\t" |
532 << "vmov" | 541 << "vmov" << getPredicate() << "\t"; |
533 << "\t"; | |
534 Dest0->emit(Func); | 542 Dest0->emit(Func); |
535 Str << ", "; | 543 Str << ", "; |
536 Src0->emit(Func); | 544 Src0->emit(Func); |
537 Str << ", "; | 545 Str << ", "; |
538 Src1->emit(Func); | 546 Src1->emit(Func); |
539 } | 547 } |
540 | 548 |
541 namespace { | 549 namespace { |
542 bool isVariableWithoutRegister(const Operand *Op) { | 550 bool isVariableWithoutRegister(const Operand *Op) { |
543 if (const auto *OpV = llvm::dyn_cast<const Variable>(Op)) { | 551 if (const auto *OpV = llvm::dyn_cast<const Variable>(Op)) { |
544 return !OpV->hasReg(); | 552 return !OpV->hasReg(); |
545 } | 553 } |
546 return false; | 554 return false; |
547 } | 555 } |
548 | 556 |
549 bool isMemoryAccess(Operand *Op) { | 557 bool isMemoryAccess(Operand *Op) { |
550 return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op); | 558 return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op); |
551 } | 559 } |
| 560 |
| 561 bool isMoveBetweenCoreAndVFPRegisters(Variable *Dest, Operand *Src) { |
| 562 const Type DestTy = Dest->getType(); |
| 563 const Type SrcTy = Src->getType(); |
| 564 assert(!(isScalarIntegerType(DestTy) && isScalarIntegerType(SrcTy)) && |
| 565 "At most one of vmov's operands can be a core register."); |
| 566 return isScalarIntegerType(DestTy) || isScalarIntegerType(SrcTy); |
| 567 } |
552 } // end of anonymous namespace | 568 } // end of anonymous namespace |
553 | 569 |
554 void InstARM32Vmov::emitSingleDestSingleSource(const Cfg *Func) const { | 570 void InstARM32Vmov::emitSingleDestSingleSource(const Cfg *Func) const { |
555 if (!BuildDefs::dump()) | 571 if (!BuildDefs::dump()) |
556 return; | 572 return; |
557 Ostream &Str = Func->getContext()->getStrEmit(); | 573 Ostream &Str = Func->getContext()->getStrEmit(); |
558 Variable *Dest = getDest(); | 574 Variable *Dest = getDest(); |
559 if (Dest->hasReg()) { | 575 if (Dest->hasReg()) { |
560 Operand *Src0 = getSrc(0); | 576 Operand *Src0 = getSrc(0); |
561 const char *ActualOpcode = isMemoryAccess(Src0) ? "vldr" : "vmov"; | 577 const char *ActualOpcode = isMemoryAccess(Src0) ? "vldr" : "vmov"; |
562 Str << "\t" << ActualOpcode << "\t"; | 578 // when vmov{c}'ing, we need to emit a width string. Otherwise, the |
| 579 // assembler might be tempted to assume we want a vector vmov{c}, and that |
| 580 // is disallowed because ARM. |
| 581 const char *WidthString = |
| 582 (isMemoryAccess(Src0) || isMoveBetweenCoreAndVFPRegisters(Dest, Src0)) |
| 583 ? "" |
| 584 : getVecWidthString(Src0->getType()); |
| 585 Str << "\t" << ActualOpcode << getPredicate() << WidthString << "\t"; |
563 Dest->emit(Func); | 586 Dest->emit(Func); |
564 Str << ", "; | 587 Str << ", "; |
565 Src0->emit(Func); | 588 Src0->emit(Func); |
566 } else { | 589 } else { |
567 Variable *Src0 = llvm::cast<Variable>(getSrc(0)); | 590 Variable *Src0 = llvm::cast<Variable>(getSrc(0)); |
568 assert(Src0->hasReg()); | 591 assert(Src0->hasReg()); |
569 Str << "\t" | 592 Str << "\t" |
570 "vstr" | 593 "vstr" << getPredicate() << "\t"; |
571 "\t"; | |
572 Src0->emit(Func); | 594 Src0->emit(Func); |
573 Str << ", "; | 595 Str << ", "; |
574 Dest->emit(Func); | 596 Dest->emit(Func); |
575 } | 597 } |
576 } | 598 } |
577 | 599 |
578 void InstARM32Vmov::emit(const Cfg *Func) const { | 600 void InstARM32Vmov::emit(const Cfg *Func) const { |
579 if (!BuildDefs::dump()) | 601 if (!BuildDefs::dump()) |
580 return; | 602 return; |
581 assert(CondARM32::AL == getPredicate()); | |
582 assert(isMultiDest() + isMultiSource() <= 1 && "Invalid vmov type."); | 603 assert(isMultiDest() + isMultiSource() <= 1 && "Invalid vmov type."); |
583 if (isMultiDest()) { | 604 if (isMultiDest()) { |
584 emitMultiDestSingleSource(Func); | 605 emitMultiDestSingleSource(Func); |
585 return; | 606 return; |
586 } | 607 } |
587 | 608 |
588 if (isMultiSource()) { | 609 if (isMultiSource()) { |
589 emitSingleDestMultiSource(Func); | 610 emitSingleDestMultiSource(Func); |
590 return; | 611 return; |
591 } | 612 } |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1038 void InstARM32Vcvt::dump(const Cfg *Func) const { | 1059 void InstARM32Vcvt::dump(const Cfg *Func) const { |
1039 if (!BuildDefs::dump()) | 1060 if (!BuildDefs::dump()) |
1040 return; | 1061 return; |
1041 Ostream &Str = Func->getContext()->getStrDump(); | 1062 Ostream &Str = Func->getContext()->getStrDump(); |
1042 dumpDest(Func); | 1063 dumpDest(Func); |
1043 Str << " = " | 1064 Str << " = " |
1044 << "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " "; | 1065 << "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " "; |
1045 dumpSources(Func); | 1066 dumpSources(Func); |
1046 } | 1067 } |
1047 | 1068 |
| 1069 void InstARM32Vcmp::emit(const Cfg *Func) const { |
| 1070 if (!BuildDefs::dump()) |
| 1071 return; |
| 1072 Ostream &Str = Func->getContext()->getStrEmit(); |
| 1073 assert(getSrcSize() == 2); |
| 1074 Str << "\t" |
| 1075 "vcmp" << getPredicate() << getVecWidthString(getSrc(0)->getType()) |
| 1076 << "\t"; |
| 1077 getSrc(0)->emit(Func); |
| 1078 Str << ", "; |
| 1079 getSrc(1)->emit(Func); |
| 1080 } |
| 1081 |
| 1082 void InstARM32Vcmp::emitIAS(const Cfg *Func) const { |
| 1083 assert(getSrcSize() == 2); |
| 1084 (void)Func; |
| 1085 llvm_unreachable("Not yet implemented"); |
| 1086 } |
| 1087 |
| 1088 void InstARM32Vcmp::dump(const Cfg *Func) const { |
| 1089 if (!BuildDefs::dump()) |
| 1090 return; |
| 1091 Ostream &Str = Func->getContext()->getStrDump(); |
| 1092 Str << "vcmp" << getPredicate() << getVecWidthString(getSrc(0)->getType()); |
| 1093 dumpSources(Func); |
| 1094 } |
| 1095 |
| 1096 void InstARM32Vmrs::emit(const Cfg *Func) const { |
| 1097 if (!BuildDefs::dump()) |
| 1098 return; |
| 1099 Ostream &Str = Func->getContext()->getStrEmit(); |
| 1100 assert(getSrcSize() == 0); |
| 1101 Str << "\t" |
| 1102 "vmrs" << getPredicate() << "\t" |
| 1103 "APSR_nzcv" |
| 1104 ", " |
| 1105 "FPSCR"; |
| 1106 } |
| 1107 |
| 1108 void InstARM32Vmrs::emitIAS(const Cfg *Func) const { |
| 1109 assert(getSrcSize() == 0); |
| 1110 (void)Func; |
| 1111 llvm_unreachable("Not yet implemented"); |
| 1112 } |
| 1113 |
| 1114 void InstARM32Vmrs::dump(const Cfg *Func) const { |
| 1115 if (!BuildDefs::dump()) |
| 1116 return; |
| 1117 Ostream &Str = Func->getContext()->getStrDump(); |
| 1118 Str << "APSR{n,z,v,c} = vmrs" << getPredicate() << "\t" |
| 1119 "FPSCR{n,z,c,v}"; |
| 1120 } |
| 1121 |
1048 void OperandARM32Mem::emit(const Cfg *Func) const { | 1122 void OperandARM32Mem::emit(const Cfg *Func) const { |
1049 if (!BuildDefs::dump()) | 1123 if (!BuildDefs::dump()) |
1050 return; | 1124 return; |
1051 Ostream &Str = Func->getContext()->getStrEmit(); | 1125 Ostream &Str = Func->getContext()->getStrEmit(); |
1052 Str << "["; | 1126 Str << "["; |
1053 getBase()->emit(Func); | 1127 getBase()->emit(Func); |
1054 switch (getAddrMode()) { | 1128 switch (getAddrMode()) { |
1055 case PostIndex: | 1129 case PostIndex: |
1056 case NegPostIndex: | 1130 case NegPostIndex: |
1057 Str << "], "; | 1131 Str << "], "; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1154 if (getShiftOp() != kNoShift) { | 1228 if (getShiftOp() != kNoShift) { |
1155 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; | 1229 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
1156 if (Func) | 1230 if (Func) |
1157 getShiftAmt()->dump(Func); | 1231 getShiftAmt()->dump(Func); |
1158 else | 1232 else |
1159 getShiftAmt()->dump(Str); | 1233 getShiftAmt()->dump(Str); |
1160 } | 1234 } |
1161 } | 1235 } |
1162 | 1236 |
1163 } // end of namespace Ice | 1237 } // end of namespace Ice |
OLD | NEW |