| 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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 | 80 |
| 81 void InstARM32Pred::dumpOpcodePred(Ostream &Str, const char *Opcode, | 81 void InstARM32Pred::dumpOpcodePred(Ostream &Str, const char *Opcode, |
| 82 Type Ty) const { | 82 Type Ty) const { |
| 83 Str << Opcode << getPredicate() << "." << Ty; | 83 Str << Opcode << getPredicate() << "." << Ty; |
| 84 } | 84 } |
| 85 | 85 |
| 86 CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { | 86 CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { |
| 87 return InstARM32CondAttributes[Cond].Opposite; | 87 return InstARM32CondAttributes[Cond].Opposite; |
| 88 } | 88 } |
| 89 | 89 |
| 90 template <> |
| 91 void InstARM32::startNextAsmInst<TextualAssembly>(const Cfg *Func) const { |
| 92 startNextInst(Func); |
| 93 Func->getContext()->getStrEmit() << "\n"; |
| 94 } |
| 95 |
| 96 template <> |
| 97 void InstARM32::startNextAsmInst<BinaryAssembly>(const Cfg *Func) const { |
| 98 (void)Func; |
| 99 } |
| 100 |
| 90 void InstARM32::startNextInst(const Cfg *Func) const { | 101 void InstARM32::startNextInst(const Cfg *Func) const { |
| 91 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>()) | 102 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>()) |
| 92 Asm->incEmitTextSize(InstSize); | 103 Asm->incEmitTextSize(InstSize); |
| 93 } | 104 } |
| 94 | 105 |
| 95 void InstARM32::emitUsingTextFixup(const Cfg *Func) const { | 106 void InstARM32::emitUsingTextFixup(const Cfg *Func) const { |
| 96 if (!BuildDefs::dump()) | 107 if (!BuildDefs::dump()) |
| 97 return; | 108 return; |
| 98 GlobalContext *Ctx = Func->getContext(); | 109 GlobalContext *Ctx = Func->getContext(); |
| 99 if (Ctx->getFlags().getDisableHybridAssembly()) { | 110 if (Ctx->getFlags().getDisableHybridAssembly()) { |
| (...skipping 1216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1316 | 1327 |
| 1317 bool isAssignedConsecutiveRegisters(const Variable *Before, | 1328 bool isAssignedConsecutiveRegisters(const Variable *Before, |
| 1318 const Variable *After) { | 1329 const Variable *After) { |
| 1319 assert(Before->hasReg()); | 1330 assert(Before->hasReg()); |
| 1320 assert(After->hasReg()); | 1331 assert(After->hasReg()); |
| 1321 return Before->getRegNum() + 1 == After->getRegNum(); | 1332 return Before->getRegNum() + 1 == After->getRegNum(); |
| 1322 } | 1333 } |
| 1323 | 1334 |
| 1324 } // end of anonymous namespace | 1335 } // end of anonymous namespace |
| 1325 | 1336 |
| 1326 void InstARM32Pop::emit(const Cfg *Func) const { | 1337 template <AssemblyOutputForm Form> |
| 1327 if (!BuildDefs::dump()) | 1338 void InstARM32Pop::assemble(const Cfg *Func) const { |
| 1339 if (Form == TextualAssembly && !BuildDefs::dump()) |
| 1328 return; | 1340 return; |
| 1329 | |
| 1330 const SizeT DestSize = Dests.size(); | |
| 1331 if (DestSize == 0) { | |
| 1332 assert(false && "Empty pop list"); | |
| 1333 return; | |
| 1334 } | |
| 1335 | |
| 1336 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 1337 | |
| 1338 Variable *Reg = Dests[0]; | |
| 1339 if (isScalarIntegerType(Reg->getType())) { | |
| 1340 // GPR push. | |
| 1341 Str << "\t" | |
| 1342 "pop" | |
| 1343 "\t{"; | |
| 1344 Reg->emit(Func); | |
| 1345 for (SizeT i = 1; i < DestSize; ++i) { | |
| 1346 Str << ", "; | |
| 1347 Reg = Dests[i]; | |
| 1348 Reg->emit(Func); | |
| 1349 } | |
| 1350 Str << "}"; | |
| 1351 return; | |
| 1352 } | |
| 1353 | |
| 1354 // VFP "s" reg push. | |
| 1355 SizeT End = DestSize - 1; | |
| 1356 SizeT Start = DestSize - 1; | |
| 1357 Reg = Dests[DestSize - 1]; | |
| 1358 Str << "\t" | |
| 1359 "vpop" | |
| 1360 "\t{"; | |
| 1361 for (SizeT i = 2; i <= DestSize; ++i) { | |
| 1362 Variable *PreviousReg = Dests[DestSize - i]; | |
| 1363 if (!isAssignedConsecutiveRegisters(PreviousReg, Reg)) { | |
| 1364 Dests[Start]->emit(Func); | |
| 1365 for (SizeT j = Start + 1; j <= End; ++j) { | |
| 1366 Str << ", "; | |
| 1367 Dests[j]->emit(Func); | |
| 1368 } | |
| 1369 startNextInst(Func); | |
| 1370 Str << "}\n\t" | |
| 1371 "vpop" | |
| 1372 "\t{"; | |
| 1373 End = DestSize - i; | |
| 1374 } | |
| 1375 Reg = PreviousReg; | |
| 1376 Start = DestSize - i; | |
| 1377 } | |
| 1378 Dests[Start]->emit(Func); | |
| 1379 for (SizeT j = Start + 1; j <= End; ++j) { | |
| 1380 Str << ", "; | |
| 1381 Dests[j]->emit(Func); | |
| 1382 } | |
| 1383 Str << "}"; | |
| 1384 } | |
| 1385 | |
| 1386 void InstARM32Pop::emitIAS(const Cfg *Func) const { | |
| 1387 // Pop can't be emitted if there are no registers to load. This should never | 1341 // Pop can't be emitted if there are no registers to load. This should never |
| 1388 // happen, but if it does, we don't need to bring Subzero down -- we just skip | 1342 // happen, but if it does, we don't need to bring Subzero down -- we just skip |
| 1389 // emitting the pop instruction (and maybe emit a nop?) The assert() is here | 1343 // emitting the pop instruction (and maybe emit a nop?) The assert() is here |
| 1390 // so that we can detect this error during development. | 1344 // so that we can detect this error during development. |
| 1391 const SizeT DestSize = Dests.size(); | 1345 const SizeT DestSize = Dests.size(); |
| 1392 if (DestSize == 0) { | 1346 if (DestSize == 0) { |
| 1393 assert(false && "Empty pop list"); | 1347 assert(false && "Empty pop list"); |
| 1394 return; | 1348 return; |
| 1395 } | 1349 } |
| 1396 | |
| 1397 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1350 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1398 const auto *Reg = llvm::cast<Variable>(Dests[0]); | 1351 const auto *Reg = llvm::cast<Variable>(Dests[0]); |
| 1399 if (isScalarIntegerType(Reg->getType())) { | 1352 if (isScalarIntegerType(Reg->getType())) { |
| 1400 // Pop GPR registers. | 1353 // Pop GPR registers. |
| 1401 SizeT IntegerCount = 0; | 1354 SizeT IntegerCount = 0; |
| 1402 ARM32::IValueT GPRegisters = 0; | 1355 ARM32::IValueT GPRegisters = 0; |
| 1403 const Variable *LastDest = nullptr; | 1356 const Variable *LastDest = nullptr; |
| 1404 for (const Variable *Var : Dests) { | 1357 for (const Variable *Var : Dests) { |
| 1405 assert(Var->hasReg() && "pop only applies to registers"); | 1358 assert(Var->hasReg() && "pop only applies to registers"); |
| 1406 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); | 1359 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); |
| 1407 LastDest = Var; | 1360 LastDest = Var; |
| 1408 GPRegisters |= (1 << Reg); | 1361 GPRegisters |= (1 << Reg); |
| 1409 ++IntegerCount; | 1362 ++IntegerCount; |
| 1410 } | 1363 } |
| 1411 switch (IntegerCount) { | 1364 switch (IntegerCount) { |
| 1412 case 0: | 1365 case 0: |
| 1413 return; | 1366 return; |
| 1414 case 1: | 1367 case 1: |
| 1415 // Note: Can only apply pop register if single register is not sp. | 1368 // Note: Can only apply pop register if single register is not sp. |
| 1416 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && | 1369 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && |
| 1417 "Effects of pop register SP is undefined!"); | 1370 "Effects of pop register SP is undefined!"); |
| 1418 Asm->pop(LastDest, CondARM32::AL); | 1371 Asm->pop<Form>(Func, LastDest, CondARM32::AL); |
| 1419 break; | 1372 break; |
| 1420 default: | 1373 default: |
| 1421 Asm->popList(GPRegisters, CondARM32::AL); | 1374 Asm->popList<Form>(Func, GPRegisters, CondARM32::AL); |
| 1422 break; | 1375 break; |
| 1423 } | 1376 } |
| 1424 } else { | 1377 } else { |
| 1425 // Pop vector/floating point registers. | 1378 // Pop vector/floating point registers. |
| 1426 const Variable *BaseReg = nullptr; | 1379 const Variable *BaseReg = nullptr; |
| 1427 SizeT RegCount = 0; | 1380 SizeT RegCount = 0; |
| 1428 for (const Variable *NextReg : Dests) { | 1381 for (const Variable *NextReg : Dests) { |
| 1429 if (BaseReg == nullptr) { | 1382 if (BaseReg == nullptr) { |
| 1430 BaseReg = NextReg; | 1383 BaseReg = NextReg; |
| 1431 RegCount = 1; | 1384 RegCount = 1; |
| 1432 } else if (RegCount < VpushVpopMaxConsecRegs && | 1385 } else if (RegCount < VpushVpopMaxConsecRegs && |
| 1433 isAssignedConsecutiveRegisters(Reg, NextReg)) { | 1386 isAssignedConsecutiveRegisters(Reg, NextReg)) { |
| 1434 ++RegCount; | 1387 ++RegCount; |
| 1435 } else { | 1388 } else { |
| 1436 Asm->vpop(BaseReg, RegCount, CondARM32::AL); | 1389 Asm->vpop<Form>(Func, BaseReg, RegCount, CondARM32::AL); |
| 1390 this->startNextAsmInst<Form>(Func); |
| 1437 BaseReg = NextReg; | 1391 BaseReg = NextReg; |
| 1438 RegCount = 1; | 1392 RegCount = 1; |
| 1439 } | 1393 } |
| 1440 Reg = NextReg; | 1394 Reg = NextReg; |
| 1441 } | 1395 } |
| 1442 if (RegCount) | 1396 if (RegCount) |
| 1443 Asm->vpop(BaseReg, RegCount, CondARM32::AL); | 1397 Asm->vpop<Form>(Func, BaseReg, RegCount, CondARM32::AL); |
| 1444 } | 1398 } |
| 1445 if (Asm->needsTextFixup()) | 1399 if (Form == TextualAssembly && Asm->needsTextFixup()) |
| 1446 emitUsingTextFixup(Func); | 1400 emitUsingTextFixup(Func); |
| 1447 } | 1401 } |
| 1448 | 1402 |
| 1449 void InstARM32Pop::dump(const Cfg *Func) const { | 1403 void InstARM32Pop::dump(const Cfg *Func) const { |
| 1450 if (!BuildDefs::dump()) | 1404 if (!BuildDefs::dump()) |
| 1451 return; | 1405 return; |
| 1452 Ostream &Str = Func->getContext()->getStrDump(); | 1406 Ostream &Str = Func->getContext()->getStrDump(); |
| 1453 Str << "pop" | 1407 Str << "pop" |
| 1454 << " "; | 1408 << " "; |
| 1455 for (SizeT I = 0; I < Dests.size(); ++I) { | 1409 for (SizeT I = 0; I < Dests.size(); ++I) { |
| 1456 if (I > 0) | 1410 if (I > 0) |
| 1457 Str << ", "; | 1411 Str << ", "; |
| 1458 Dests[I]->dump(Func); | 1412 Dests[I]->dump(Func); |
| 1459 } | 1413 } |
| 1460 } | 1414 } |
| 1461 | 1415 |
| 1462 void InstARM32Push::emit(const Cfg *Func) const { | 1416 template <AssemblyOutputForm Form> |
| 1463 if (!BuildDefs::dump()) | 1417 void InstARM32Push::assemble(const Cfg *Func) const { |
| 1418 if (Form == TextualAssembly && !BuildDefs::dump()) |
| 1464 return; | 1419 return; |
| 1465 | |
| 1466 // Push can't be emitted if there are no registers to save. This should never | 1420 // Push can't be emitted if there are no registers to save. This should never |
| 1467 // happen, but if it does, we don't need to bring Subzero down -- we just skip | 1421 // happen, but if it does, we don't need to bring Subzero down -- we just skip |
| 1468 // emitting the push instruction (and maybe emit a nop?) The assert() is here | 1422 // emitting the push instruction (and maybe emit a nop?) The assert() is here |
| 1469 // so that we can detect this error during development. | |
| 1470 const SizeT SrcSize = getSrcSize(); | |
| 1471 if (SrcSize == 0) { | |
| 1472 assert(false && "Empty push list"); | |
| 1473 return; | |
| 1474 } | |
| 1475 | |
| 1476 Ostream &Str = Func->getContext()->getStrEmit(); | |
| 1477 | |
| 1478 const auto *Reg = llvm::cast<Variable>(getSrc(0)); | |
| 1479 if (isScalarIntegerType(Reg->getType())) { | |
| 1480 // GPR push. | |
| 1481 Str << "\t" | |
| 1482 "push" | |
| 1483 "\t{"; | |
| 1484 Reg->emit(Func); | |
| 1485 for (SizeT i = 1; i < SrcSize; ++i) { | |
| 1486 Str << ", "; | |
| 1487 getSrc(i)->emit(Func); | |
| 1488 } | |
| 1489 Str << "}"; | |
| 1490 return; | |
| 1491 } | |
| 1492 | |
| 1493 // VFP "s" reg push. | |
| 1494 Str << "\t" | |
| 1495 "vpush" | |
| 1496 "\t{"; | |
| 1497 Reg->emit(Func); | |
| 1498 SizeT RegCount = 1; | |
| 1499 for (SizeT i = 1; i < SrcSize; ++i) { | |
| 1500 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); | |
| 1501 if (RegCount < VpushVpopMaxConsecRegs && | |
| 1502 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1503 ++RegCount; | |
| 1504 Str << ", "; | |
| 1505 } else { | |
| 1506 startNextInst(Func); | |
| 1507 RegCount = 1; | |
| 1508 Str << "}\n\t" | |
| 1509 "vpush" | |
| 1510 "\t{"; | |
| 1511 } | |
| 1512 Reg = NextReg; | |
| 1513 Reg->emit(Func); | |
| 1514 } | |
| 1515 Str << "}"; | |
| 1516 } | |
| 1517 | |
| 1518 void InstARM32Push::emitIAS(const Cfg *Func) const { | |
| 1519 // Push can't be emitted if there are no registers to save. This should never | |
| 1520 // happen, but if it does, we don't need to bring Subzero down -- we just skip | |
| 1521 // emitting the push instruction (and maybe emit a nop?) The assert() is here | |
| 1522 // so that we can detect this error during development. | 1423 // so that we can detect this error during development. |
| 1523 const SizeT SrcSize = getSrcSize(); | 1424 const SizeT SrcSize = getSrcSize(); |
| 1524 if (SrcSize == 0) { | 1425 if (SrcSize == 0) { |
| 1525 assert(false && "Empty push list"); | 1426 assert(false && "Empty push list"); |
| 1526 return; | 1427 return; |
| 1527 } | 1428 } |
| 1528 | 1429 |
| 1529 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1430 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1530 const auto *Reg = llvm::cast<Variable>(getSrc(0)); | 1431 const auto *Reg = llvm::cast<Variable>(getSrc(0)); |
| 1531 if (isScalarIntegerType(Reg->getType())) { | 1432 if (isScalarIntegerType(Reg->getType())) { |
| 1532 // Push GPR registers. | 1433 // Push GPR registers. |
| 1533 SizeT IntegerCount = 0; | 1434 SizeT IntegerCount = 0; |
| 1534 ARM32::IValueT GPRegisters = 0; | 1435 ARM32::IValueT GPRegisters = 0; |
| 1535 const Variable *LastSrc = nullptr; | 1436 const Variable *LastSrc = nullptr; |
| 1536 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { | 1437 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { |
| 1537 const auto *Var = llvm::cast<Variable>(getSrc(Index)); | 1438 const auto *Var = llvm::cast<Variable>(getSrc(Index)); |
| 1538 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); | 1439 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); |
| 1539 assert(Reg != RegARM32::Encoded_Not_GPR); | 1440 assert(Reg != RegARM32::Encoded_Not_GPR); |
| 1540 LastSrc = Var; | 1441 LastSrc = Var; |
| 1541 GPRegisters |= (1 << Reg); | 1442 GPRegisters |= (1 << Reg); |
| 1542 ++IntegerCount; | 1443 ++IntegerCount; |
| 1543 } | 1444 } |
| 1544 switch (IntegerCount) { | 1445 switch (IntegerCount) { |
| 1545 case 0: | 1446 case 0: |
| 1546 return; | 1447 return; |
| 1547 case 1: { | 1448 case 1: { |
| 1548 // Note: Can only apply push register if single register is not sp. | 1449 // Note: Can only apply push register if single register is not sp. |
| 1549 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && | 1450 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && |
| 1550 "Effects of push register SP is undefined!"); | 1451 "Effects of push register SP is undefined!"); |
| 1551 Asm->push(LastSrc, CondARM32::AL); | 1452 Asm->push<Form>(Func, LastSrc, CondARM32::AL); |
| 1552 break; | 1453 break; |
| 1553 } | 1454 } |
| 1554 default: | 1455 default: |
| 1555 Asm->pushList(GPRegisters, CondARM32::AL); | 1456 Asm->pushList<Form>(Func, GPRegisters, CondARM32::AL); |
| 1556 break; | 1457 break; |
| 1557 } | 1458 } |
| 1558 } else { | 1459 } else { |
| 1559 // Push vector/Floating point registers. | 1460 // Push vector/Floating point registers. |
| 1560 const Variable *BaseReg = Reg; | 1461 const Variable *BaseReg = Reg; |
| 1561 SizeT RegCount = 1; | 1462 SizeT RegCount = 1; |
| 1562 for (SizeT i = 1; i < SrcSize; ++i) { | 1463 for (SizeT i = 1; i < SrcSize; ++i) { |
| 1563 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); | 1464 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); |
| 1564 if (RegCount < VpushVpopMaxConsecRegs && | 1465 if (RegCount < VpushVpopMaxConsecRegs && |
| 1565 isAssignedConsecutiveRegisters(Reg, NextReg)) { | 1466 isAssignedConsecutiveRegisters(Reg, NextReg)) { |
| 1566 ++RegCount; | 1467 ++RegCount; |
| 1567 } else { | 1468 } else { |
| 1568 Asm->vpush(BaseReg, RegCount, CondARM32::AL); | 1469 Asm->vpush<Form>(Func, BaseReg, RegCount, CondARM32::AL); |
| 1569 BaseReg = NextReg; | 1470 BaseReg = NextReg; |
| 1570 RegCount = 1; | 1471 RegCount = 1; |
| 1571 } | 1472 } |
| 1572 Reg = NextReg; | 1473 Reg = NextReg; |
| 1573 } | 1474 } |
| 1574 Asm->vpush(BaseReg, RegCount, CondARM32::AL); | 1475 Asm->vpush<Form>(Func, BaseReg, RegCount, CondARM32::AL); |
| 1575 } | 1476 } |
| 1576 if (Asm->needsTextFixup()) | 1477 if (Form == TextualAssembly && Asm->needsTextFixup()) |
| 1577 emitUsingTextFixup(Func); | 1478 emitUsingTextFixup(Func); |
| 1578 } | 1479 } |
| 1579 | 1480 |
| 1580 void InstARM32Push::dump(const Cfg *Func) const { | 1481 void InstARM32Push::dump(const Cfg *Func) const { |
| 1581 if (!BuildDefs::dump()) | 1482 if (!BuildDefs::dump()) |
| 1582 return; | 1483 return; |
| 1583 Ostream &Str = Func->getContext()->getStrDump(); | 1484 Ostream &Str = Func->getContext()->getStrDump(); |
| 1584 Str << "push" | 1485 Str << "push" |
| 1585 << " "; | 1486 << " "; |
| 1586 dumpSources(Func); | 1487 dumpSources(Func); |
| (...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2145 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; | 2046 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; |
| 2146 | 2047 |
| 2147 template class InstARM32FourAddrGPR<InstARM32::Mla>; | 2048 template class InstARM32FourAddrGPR<InstARM32::Mla>; |
| 2148 template class InstARM32FourAddrGPR<InstARM32::Mls>; | 2049 template class InstARM32FourAddrGPR<InstARM32::Mls>; |
| 2149 | 2050 |
| 2150 template class InstARM32CmpLike<InstARM32::Cmn>; | 2051 template class InstARM32CmpLike<InstARM32::Cmn>; |
| 2151 template class InstARM32CmpLike<InstARM32::Cmp>; | 2052 template class InstARM32CmpLike<InstARM32::Cmp>; |
| 2152 template class InstARM32CmpLike<InstARM32::Tst>; | 2053 template class InstARM32CmpLike<InstARM32::Tst>; |
| 2153 | 2054 |
| 2154 } // end of namespace Ice | 2055 } // end of namespace Ice |
| OLD | NEW |