Chromium Code Reviews| 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 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 621 if (!Reg->hasReg()) { | 621 if (!Reg->hasReg()) { |
| 622 llvm::report_fatal_error("Push/pop operand does not have a register " | 622 llvm::report_fatal_error("Push/pop operand does not have a register " |
| 623 "assigned to it."); | 623 "assigned to it."); |
| 624 } | 624 } |
| 625 | 625 |
| 626 PreviousTy = Reg->getType(); | 626 PreviousTy = Reg->getType(); |
| 627 } | 627 } |
| 628 } | 628 } |
| 629 } // end of anonymous namespace | 629 } // end of anonymous namespace |
| 630 | 630 |
| 631 void InstARM32RegisterStackOp::emit(const Cfg *Func) const { | |
| 632 if (!BuildDefs::dump()) | |
| 633 return; | |
| 634 emitUsingForm(Func, TextualOutput); | |
| 635 } | |
| 636 | |
| 637 void InstARM32RegisterStackOp::emitIAS(const Cfg *Func) const { | |
| 638 emitUsingForm(Func, BinaryOutput); | |
| 639 assert(!Func->getAssembler<ARM32::AssemblerARM32>()->needsTextFixup()); | |
| 640 } | |
| 641 | |
| 642 void InstARM32RegisterStackOp::dump(const Cfg *Func) const { | |
| 643 if (!BuildDefs::dump()) | |
| 644 return; | |
| 645 Ostream &Str = Func->getContext()->getStrDump(); | |
| 646 Str << getOpcode() << " "; | |
| 647 SizeT NumRegs = getNumStackRegs(); | |
| 648 for (SizeT I = 0; I < NumRegs; ++I) { | |
| 649 if (I > 0) | |
| 650 Str << ", "; | |
| 651 getStackReg(I)->dump(Func); | |
| 652 } | |
| 653 } | |
| 654 | |
| 655 void InstARM32RegisterStackOp::emitGPRsAsText(const Cfg *Func) const { | |
| 656 if (!BuildDefs::dump()) | |
| 657 return; | |
| 658 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 659 Str << "\t" << getOpcode() << "\t{"; | |
| 660 getStackReg(0)->emit(Func); | |
| 661 const SizeT NumRegs = getNumStackRegs(); | |
| 662 for (SizeT i = 1; i < NumRegs; ++i) { | |
| 663 Str << ", "; | |
| 664 getStackReg(i)->emit(Func); | |
| 665 } | |
| 666 Str << "}"; | |
| 667 } | |
| 668 | |
| 669 void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func, | |
| 670 const Variable *BaseReg, | |
| 671 SizeT RegCount) const { | |
| 672 if (!BuildDefs::dump()) | |
| 673 return; | |
| 674 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 675 Str << "\t" | |
| 676 << "v" << getOpcode() << "\t{"; | |
|
John
2016/01/11 13:40:36
optional: I am not a big fan of this strategy. I p
Karl
2016/01/11 17:59:44
Fixed by adding virtual to differentiate GPR opcod
| |
| 677 bool IsFirst = true; | |
| 678 IValueT Base = RegARM32::getEncodedSReg(BaseReg->getRegNum()); | |
| 679 for (SizeT i = 0; i < RegCount; ++i) { | |
| 680 if (IsFirst) | |
| 681 IsFirst = false; | |
| 682 else | |
| 683 Str << ", "; | |
| 684 Str << RegARM32::getSRegName(Base + i); | |
| 685 } | |
| 686 Str << "}"; | |
| 687 } | |
| 688 | |
| 689 namespace { | |
| 690 | |
| 691 bool isAssignedConsecutiveRegisters(const Variable *Before, | |
| 692 const Variable *After) { | |
| 693 assert(Before->hasReg()); | |
| 694 assert(After->hasReg()); | |
| 695 return Before->getRegNum() + 1 == After->getRegNum(); | |
| 696 } | |
| 697 | |
| 698 } // end of anonymous namespace | |
| 699 | |
| 700 void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func, | |
| 701 const OutputForm Form) const { | |
| 702 SizeT NumRegs = getNumStackRegs(); | |
| 703 assert(NumRegs); | |
| 704 | |
| 705 const auto *Reg = llvm::cast<Variable>(getStackReg(0)); | |
| 706 if (isScalarIntegerType(Reg->getType())) { | |
| 707 // Pop GPR registers. | |
| 708 SizeT IntegerCount = 0; | |
| 709 ARM32::IValueT GPRegisters = 0; | |
| 710 const Variable *LastDest = nullptr; | |
| 711 for (SizeT i = 0; i < NumRegs; ++i) { | |
| 712 const Variable *Var = getStackReg(i); | |
| 713 assert(Var->hasReg() && "stack op only applies to registers"); | |
| 714 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); | |
| 715 LastDest = Var; | |
| 716 GPRegisters |= (1 << Reg); | |
| 717 ++IntegerCount; | |
| 718 } | |
| 719 if (IntegerCount == 1) { | |
| 720 emitSingleGPR(Func, Form, LastDest); | |
| 721 } else { | |
| 722 emitMultipleGPRs(Func, Form, GPRegisters); | |
| 723 } | |
| 724 } else { | |
| 725 // Pop vector/floating point registers. | |
| 726 const Variable *BaseReg = nullptr; | |
| 727 SizeT RegCount = 0; | |
| 728 for (SizeT i = 0; i < NumRegs; ++i) { | |
| 729 const Variable *NextReg = getStackReg(i); | |
| 730 if (BaseReg == nullptr) { | |
| 731 BaseReg = NextReg; | |
| 732 RegCount = 1; | |
| 733 } else if (RegCount < VpushVpopMaxConsecRegs && | |
| 734 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 735 ++RegCount; | |
| 736 } else { | |
| 737 emitSRegs(Func, Form, BaseReg, RegCount); | |
| 738 if (Form == TextualOutput && BuildDefs::dump()) { | |
| 739 startNextInst(Func); | |
| 740 Func->getContext()->getStrEmit() << "\n"; | |
| 741 } | |
| 742 BaseReg = NextReg; | |
| 743 RegCount = 1; | |
| 744 } | |
| 745 Reg = NextReg; | |
| 746 } | |
| 747 if (RegCount) { | |
| 748 emitSRegs(Func, Form, BaseReg, RegCount); | |
| 749 } | |
| 750 } | |
| 751 } | |
| 752 | |
| 631 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) | 753 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) |
| 632 : InstARM32(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { | 754 : InstARM32RegisterStackOp(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { |
| 633 // Track modifications to Dests separately via FakeDefs. Also, a pop | 755 // Track modifications to Dests separately via FakeDefs. Also, a pop |
| 634 // instruction affects the stack pointer and so it should not be allowed to | 756 // instruction affects the stack pointer and so it should not be allowed to |
| 635 // be automatically dead-code eliminated. This is automatic since we leave | 757 // be automatically dead-code eliminated. This is automatic since we leave |
| 636 // the Dest as nullptr. | 758 // the Dest as nullptr. |
| 637 validatePushOrPopRegisterListOrDie(Dests); | 759 validatePushOrPopRegisterListOrDie(Dests); |
| 638 } | 760 } |
| 639 | 761 |
| 640 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) | 762 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) |
| 641 : InstARM32(Func, InstARM32::Push, Srcs.size(), nullptr) { | 763 : InstARM32RegisterStackOp(Func, InstARM32::Push, Srcs.size(), nullptr) { |
| 642 validatePushOrPopRegisterListOrDie(Srcs); | 764 validatePushOrPopRegisterListOrDie(Srcs); |
| 643 for (Variable *Source : Srcs) { | 765 for (Variable *Source : Srcs) { |
| 644 addSource(Source); | 766 addSource(Source); |
| 645 } | 767 } |
| 646 } | 768 } |
| 647 | 769 |
| 648 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) | 770 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
| 649 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { | 771 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { |
| 650 addSource(LR); | 772 addSource(LR); |
| 651 if (Source) | 773 if (Source) |
| (...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1306 } | 1428 } |
| 1307 | 1429 |
| 1308 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { | 1430 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { |
| 1309 assert(getSrcSize() == 1); | 1431 assert(getSrcSize() == 1); |
| 1310 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1432 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1311 Asm->uxt(getDest(), getSrc(0), getPredicate()); | 1433 Asm->uxt(getDest(), getSrc(0), getPredicate()); |
| 1312 if (Asm->needsTextFixup()) | 1434 if (Asm->needsTextFixup()) |
| 1313 emitUsingTextFixup(Func); | 1435 emitUsingTextFixup(Func); |
| 1314 } | 1436 } |
| 1315 | 1437 |
| 1316 namespace { | 1438 const char *InstARM32Pop::getOpcode() const { return "pop"; } |
| 1317 | 1439 |
| 1318 bool isAssignedConsecutiveRegisters(const Variable *Before, | 1440 Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; } |
| 1319 const Variable *After) { | |
| 1320 assert(Before->hasReg()); | |
| 1321 assert(After->hasReg()); | |
| 1322 return Before->getRegNum() + 1 == After->getRegNum(); | |
| 1323 } | |
| 1324 | 1441 |
| 1325 } // end of anonymous namespace | 1442 SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); } |
| 1326 | 1443 |
| 1327 void InstARM32Pop::emit(const Cfg *Func) const { | 1444 void InstARM32Pop::emitSingleGPR(const Cfg *Func, const OutputForm Form, |
| 1328 if (!BuildDefs::dump()) | 1445 const Variable *Reg) const { |
| 1446 switch (Form) { | |
| 1447 case TextualOutput: | |
| 1448 emitGPRsAsText(Func); | |
| 1329 return; | 1449 return; |
| 1330 | 1450 case BinaryOutput: |
| 1331 const SizeT DestSize = Dests.size(); | 1451 Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL); |
| 1332 if (DestSize == 0) { | |
| 1333 assert(false && "Empty pop list"); | |
| 1334 return; | 1452 return; |
| 1335 } | 1453 } |
| 1336 | |
| 1337 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 1338 | |
| 1339 Variable *Reg = Dests[0]; | |
| 1340 if (isScalarIntegerType(Reg->getType())) { | |
| 1341 // GPR push. | |
| 1342 Str << "\t" | |
| 1343 "pop" | |
| 1344 "\t{"; | |
| 1345 Reg->emit(Func); | |
| 1346 for (SizeT i = 1; i < DestSize; ++i) { | |
| 1347 Str << ", "; | |
| 1348 Reg = Dests[i]; | |
| 1349 Reg->emit(Func); | |
| 1350 } | |
| 1351 Str << "}"; | |
| 1352 return; | |
| 1353 } | |
| 1354 | |
| 1355 // VFP "s" reg push. | |
| 1356 SizeT End = DestSize - 1; | |
| 1357 SizeT Start = DestSize - 1; | |
| 1358 Reg = Dests[DestSize - 1]; | |
| 1359 Str << "\t" | |
| 1360 "vpop" | |
| 1361 "\t{"; | |
| 1362 for (SizeT i = 2; i <= DestSize; ++i) { | |
| 1363 Variable *PreviousReg = Dests[DestSize - i]; | |
| 1364 if (!isAssignedConsecutiveRegisters(PreviousReg, Reg)) { | |
| 1365 Dests[Start]->emit(Func); | |
| 1366 for (SizeT j = Start + 1; j <= End; ++j) { | |
| 1367 Str << ", "; | |
| 1368 Dests[j]->emit(Func); | |
| 1369 } | |
| 1370 startNextInst(Func); | |
| 1371 Str << "}\n\t" | |
| 1372 "vpop" | |
| 1373 "\t{"; | |
| 1374 End = DestSize - i; | |
| 1375 } | |
| 1376 Reg = PreviousReg; | |
| 1377 Start = DestSize - i; | |
| 1378 } | |
| 1379 Dests[Start]->emit(Func); | |
| 1380 for (SizeT j = Start + 1; j <= End; ++j) { | |
| 1381 Str << ", "; | |
| 1382 Dests[j]->emit(Func); | |
| 1383 } | |
| 1384 Str << "}"; | |
| 1385 } | |
| 1386 | |
| 1387 void InstARM32Pop::emitIAS(const Cfg *Func) const { | |
| 1388 // Pop can't be emitted if there are no registers to load. This should never | |
| 1389 // happen, but if it does, we don't need to bring Subzero down -- we just skip | |
| 1390 // emitting the pop instruction (and maybe emit a nop?) The assert() is here | |
| 1391 // so that we can detect this error during development. | |
| 1392 const SizeT DestSize = Dests.size(); | |
| 1393 if (DestSize == 0) { | |
| 1394 assert(false && "Empty pop list"); | |
| 1395 return; | |
| 1396 } | |
| 1397 | |
| 1398 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | |
| 1399 const auto *Reg = llvm::cast<Variable>(Dests[0]); | |
| 1400 if (isScalarIntegerType(Reg->getType())) { | |
| 1401 // Pop GPR registers. | |
| 1402 SizeT IntegerCount = 0; | |
| 1403 ARM32::IValueT GPRegisters = 0; | |
| 1404 const Variable *LastDest = nullptr; | |
| 1405 for (const Variable *Var : Dests) { | |
| 1406 assert(Var->hasReg() && "pop only applies to registers"); | |
| 1407 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); | |
| 1408 LastDest = Var; | |
| 1409 GPRegisters |= (1 << Reg); | |
| 1410 ++IntegerCount; | |
| 1411 } | |
| 1412 switch (IntegerCount) { | |
| 1413 case 0: | |
| 1414 return; | |
| 1415 case 1: | |
| 1416 // Note: Can only apply pop register if single register is not sp. | |
| 1417 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && | |
| 1418 "Effects of pop register SP is undefined!"); | |
| 1419 Asm->pop(LastDest, CondARM32::AL); | |
| 1420 break; | |
| 1421 default: | |
| 1422 Asm->popList(GPRegisters, CondARM32::AL); | |
| 1423 break; | |
| 1424 } | |
| 1425 } else { | |
| 1426 // Pop vector/floating point registers. | |
| 1427 const Variable *BaseReg = nullptr; | |
| 1428 SizeT RegCount = 0; | |
| 1429 for (const Variable *NextReg : Dests) { | |
| 1430 if (BaseReg == nullptr) { | |
| 1431 BaseReg = NextReg; | |
| 1432 RegCount = 1; | |
| 1433 } else if (RegCount < VpushVpopMaxConsecRegs && | |
| 1434 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1435 ++RegCount; | |
| 1436 } else { | |
| 1437 Asm->vpop(BaseReg, RegCount, CondARM32::AL); | |
| 1438 BaseReg = NextReg; | |
| 1439 RegCount = 1; | |
| 1440 } | |
| 1441 Reg = NextReg; | |
| 1442 } | |
| 1443 if (RegCount) | |
| 1444 Asm->vpop(BaseReg, RegCount, CondARM32::AL); | |
| 1445 } | |
| 1446 if (Asm->needsTextFixup()) | |
| 1447 emitUsingTextFixup(Func); | |
| 1448 } | |
| 1449 | |
| 1450 void InstARM32Pop::dump(const Cfg *Func) const { | |
| 1451 if (!BuildDefs::dump()) | |
| 1452 return; | |
| 1453 Ostream &Str = Func->getContext()->getStrDump(); | |
| 1454 Str << "pop" | |
| 1455 << " "; | |
| 1456 for (SizeT I = 0; I < Dests.size(); ++I) { | |
| 1457 if (I > 0) | |
| 1458 Str << ", "; | |
| 1459 Dests[I]->dump(Func); | |
| 1460 } | |
| 1461 } | 1454 } |
| 1462 | 1455 |
| 1463 void InstARM32Push::emit(const Cfg *Func) const { | 1456 void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const OutputForm Form, |
| 1464 if (!BuildDefs::dump()) | 1457 IValueT Registers) const { |
| 1458 switch (Form) { | |
| 1459 case TextualOutput: | |
| 1460 emitGPRsAsText(Func); | |
| 1465 return; | 1461 return; |
| 1466 | 1462 case BinaryOutput: |
| 1467 // Push can't be emitted if there are no registers to save. This should never | 1463 Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers, |
| 1468 // happen, but if it does, we don't need to bring Subzero down -- we just skip | 1464 CondARM32::AL); |
| 1469 // emitting the push instruction (and maybe emit a nop?) The assert() is here | |
| 1470 // so that we can detect this error during development. | |
| 1471 const SizeT SrcSize = getSrcSize(); | |
| 1472 if (SrcSize == 0) { | |
| 1473 assert(false && "Empty push list"); | |
| 1474 return; | 1465 return; |
| 1475 } | 1466 } |
| 1467 } | |
| 1476 | 1468 |
| 1477 Ostream &Str = Func->getContext()->getStrEmit(); | 1469 void InstARM32Pop::emitSRegs(const Cfg *Func, const OutputForm Form, |
| 1478 | 1470 const Variable *BaseReg, SizeT RegCount) const { |
| 1479 const auto *Reg = llvm::cast<Variable>(getSrc(0)); | 1471 switch (Form) { |
| 1480 if (isScalarIntegerType(Reg->getType())) { | 1472 case TextualOutput: |
| 1481 // GPR push. | 1473 emitSRegsAsText(Func, BaseReg, RegCount); |
| 1482 Str << "\t" | 1474 return; |
| 1483 "push" | 1475 case BinaryOutput: |
| 1484 "\t{"; | 1476 Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount, |
| 1485 Reg->emit(Func); | 1477 CondARM32::AL); |
| 1486 for (SizeT i = 1; i < SrcSize; ++i) { | |
| 1487 Str << ", "; | |
| 1488 getSrc(i)->emit(Func); | |
| 1489 } | |
| 1490 Str << "}"; | |
| 1491 return; | 1478 return; |
| 1492 } | 1479 } |
| 1493 | |
| 1494 // VFP "s" reg push. | |
| 1495 Str << "\t" | |
| 1496 "vpush" | |
| 1497 "\t{"; | |
| 1498 Reg->emit(Func); | |
| 1499 SizeT RegCount = 1; | |
| 1500 for (SizeT i = 1; i < SrcSize; ++i) { | |
| 1501 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); | |
| 1502 if (RegCount < VpushVpopMaxConsecRegs && | |
| 1503 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1504 ++RegCount; | |
| 1505 Str << ", "; | |
| 1506 } else { | |
| 1507 startNextInst(Func); | |
| 1508 RegCount = 1; | |
| 1509 Str << "}\n\t" | |
| 1510 "vpush" | |
| 1511 "\t{"; | |
| 1512 } | |
| 1513 Reg = NextReg; | |
| 1514 Reg->emit(Func); | |
| 1515 } | |
| 1516 Str << "}"; | |
| 1517 } | 1480 } |
| 1518 | 1481 |
| 1519 void InstARM32Push::emitIAS(const Cfg *Func) const { | 1482 const char *InstARM32Push::getOpcode() const { return "push"; } |
| 1520 // Push can't be emitted if there are no registers to save. This should never | 1483 |
| 1521 // happen, but if it does, we don't need to bring Subzero down -- we just skip | 1484 Variable *InstARM32Push::getStackReg(SizeT Index) const { |
| 1522 // emitting the push instruction (and maybe emit a nop?) The assert() is here | 1485 return llvm::cast<Variable>(getSrc(Index)); |
| 1523 // so that we can detect this error during development. | 1486 } |
| 1524 const SizeT SrcSize = getSrcSize(); | 1487 |
| 1525 if (SrcSize == 0) { | 1488 SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); } |
| 1526 assert(false && "Empty push list"); | 1489 |
| 1490 void InstARM32Push::emitSingleGPR(const Cfg *Func, const OutputForm Form, | |
| 1491 const Variable *Reg) const { | |
| 1492 switch (Form) { | |
| 1493 case TextualOutput: | |
| 1494 emitGPRsAsText(Func); | |
| 1495 return; | |
| 1496 case BinaryOutput: | |
| 1497 Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL); | |
| 1527 return; | 1498 return; |
| 1528 } | 1499 } |
| 1529 | |
| 1530 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | |
| 1531 const auto *Reg = llvm::cast<Variable>(getSrc(0)); | |
| 1532 if (isScalarIntegerType(Reg->getType())) { | |
| 1533 // Push GPR registers. | |
| 1534 SizeT IntegerCount = 0; | |
| 1535 ARM32::IValueT GPRegisters = 0; | |
| 1536 const Variable *LastSrc = nullptr; | |
| 1537 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { | |
| 1538 const auto *Var = llvm::cast<Variable>(getSrc(Index)); | |
| 1539 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); | |
| 1540 assert(Reg != RegARM32::Encoded_Not_GPR); | |
| 1541 LastSrc = Var; | |
| 1542 GPRegisters |= (1 << Reg); | |
| 1543 ++IntegerCount; | |
| 1544 } | |
| 1545 switch (IntegerCount) { | |
| 1546 case 0: | |
| 1547 return; | |
| 1548 case 1: { | |
| 1549 // Note: Can only apply push register if single register is not sp. | |
| 1550 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && | |
| 1551 "Effects of push register SP is undefined!"); | |
| 1552 Asm->push(LastSrc, CondARM32::AL); | |
| 1553 break; | |
| 1554 } | |
| 1555 default: | |
| 1556 Asm->pushList(GPRegisters, CondARM32::AL); | |
| 1557 break; | |
| 1558 } | |
| 1559 } else { | |
| 1560 // Push vector/Floating point registers. | |
| 1561 const Variable *BaseReg = Reg; | |
| 1562 SizeT RegCount = 1; | |
| 1563 for (SizeT i = 1; i < SrcSize; ++i) { | |
| 1564 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); | |
| 1565 if (RegCount < VpushVpopMaxConsecRegs && | |
| 1566 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1567 ++RegCount; | |
| 1568 } else { | |
| 1569 Asm->vpush(BaseReg, RegCount, CondARM32::AL); | |
| 1570 BaseReg = NextReg; | |
| 1571 RegCount = 1; | |
| 1572 } | |
| 1573 Reg = NextReg; | |
| 1574 } | |
| 1575 Asm->vpush(BaseReg, RegCount, CondARM32::AL); | |
| 1576 } | |
| 1577 if (Asm->needsTextFixup()) | |
| 1578 emitUsingTextFixup(Func); | |
| 1579 } | 1500 } |
| 1580 | 1501 |
| 1581 void InstARM32Push::dump(const Cfg *Func) const { | 1502 void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const OutputForm Form, |
| 1582 if (!BuildDefs::dump()) | 1503 IValueT Registers) const { |
| 1504 switch (Form) { | |
| 1505 case TextualOutput: | |
| 1506 emitGPRsAsText(Func); | |
| 1583 return; | 1507 return; |
| 1584 Ostream &Str = Func->getContext()->getStrDump(); | 1508 case BinaryOutput: |
| 1585 Str << "push" | 1509 Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers, |
| 1586 << " "; | 1510 CondARM32::AL); |
| 1587 dumpSources(Func); | 1511 return; |
| 1512 } | |
| 1513 } | |
| 1514 | |
| 1515 void InstARM32Push::emitSRegs(const Cfg *Func, const OutputForm Form, | |
| 1516 const Variable *BaseReg, SizeT RegCount) const { | |
| 1517 switch (Form) { | |
| 1518 case TextualOutput: | |
| 1519 emitSRegsAsText(Func, BaseReg, RegCount); | |
| 1520 return; | |
| 1521 case BinaryOutput: | |
| 1522 Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount, | |
| 1523 CondARM32::AL); | |
| 1524 return; | |
| 1525 } | |
| 1588 } | 1526 } |
| 1589 | 1527 |
| 1590 void InstARM32Ret::emit(const Cfg *Func) const { | 1528 void InstARM32Ret::emit(const Cfg *Func) const { |
| 1591 if (!BuildDefs::dump()) | 1529 if (!BuildDefs::dump()) |
| 1592 return; | 1530 return; |
| 1593 assert(getSrcSize() > 0); | 1531 assert(getSrcSize() > 0); |
| 1594 auto *LR = llvm::cast<Variable>(getSrc(0)); | 1532 auto *LR = llvm::cast<Variable>(getSrc(0)); |
| 1595 assert(LR->hasReg()); | 1533 assert(LR->hasReg()); |
| 1596 assert(LR->getRegNum() == RegARM32::Reg_lr); | 1534 assert(LR->getRegNum() == RegARM32::Reg_lr); |
| 1597 Ostream &Str = Func->getContext()->getStrEmit(); | 1535 Ostream &Str = Func->getContext()->getStrEmit(); |
| (...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2147 | 2085 |
| 2148 template class InstARM32FourAddrGPR<InstARM32::Mla>; | 2086 template class InstARM32FourAddrGPR<InstARM32::Mla>; |
| 2149 template class InstARM32FourAddrGPR<InstARM32::Mls>; | 2087 template class InstARM32FourAddrGPR<InstARM32::Mls>; |
| 2150 | 2088 |
| 2151 template class InstARM32CmpLike<InstARM32::Cmn>; | 2089 template class InstARM32CmpLike<InstARM32::Cmn>; |
| 2152 template class InstARM32CmpLike<InstARM32::Cmp>; | 2090 template class InstARM32CmpLike<InstARM32::Cmp>; |
| 2153 template class InstARM32CmpLike<InstARM32::Tst>; | 2091 template class InstARM32CmpLike<InstARM32::Tst>; |
| 2154 | 2092 |
| 2155 } // end of namespace ARM32 | 2093 } // end of namespace ARM32 |
| 2156 } // end of namespace Ice | 2094 } // end of namespace Ice |
| OLD | NEW |