Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(582)

Side by Side Diff: src/IceInstARM32.cpp

Issue 1535233002: Refactor PUSH/POP in ARM assemblers. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Do some more cleanups. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698