| 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 |
| 11 /// \brief Implements the InstARM32 and OperandARM32 classes, primarily the | 11 /// \brief Implements the InstARM32 and OperandARM32 classes, primarily the |
| 12 /// constructors and the dump()/emit() methods. | 12 /// constructors and the dump()/emit() methods. |
| 13 /// | 13 /// |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #include "IceInstARM32.h" | 16 #include "IceInstARM32.h" |
| 17 | 17 |
| 18 #include "IceAssemblerARM32.h" | 18 #include "IceAssemblerARM32.h" |
| 19 #include "IceCfg.h" | 19 #include "IceCfg.h" |
| 20 #include "IceCfgNode.h" | 20 #include "IceCfgNode.h" |
| 21 #include "IceInst.h" | 21 #include "IceInst.h" |
| 22 #include "IceOperand.h" | 22 #include "IceOperand.h" |
| 23 #include "IceRegistersARM32.h" | 23 #include "IceRegistersARM32.h" |
| 24 #include "IceTargetLoweringARM32.h" | 24 #include "IceTargetLoweringARM32.h" |
| 25 | 25 |
| 26 namespace Ice { | 26 namespace Ice { |
| 27 | 27 |
| 28 namespace { | 28 namespace { |
| 29 | 29 |
| 30 // maximum number of registers allowed in vpush/vpop. |
| 31 static constexpr SizeT VpushVpopMaxConsecRegs = 16; |
| 32 |
| 30 const struct TypeARM32Attributes_ { | 33 const struct TypeARM32Attributes_ { |
| 31 const char *WidthString; // b, h, <blank>, or d | 34 const char *WidthString; // b, h, <blank>, or d |
| 32 const char *VecWidthString; // i8, i16, i32, f32, f64 | 35 const char *VecWidthString; // i8, i16, i32, f32, f64 |
| 33 int8_t SExtAddrOffsetBits; | 36 int8_t SExtAddrOffsetBits; |
| 34 int8_t ZExtAddrOffsetBits; | 37 int8_t ZExtAddrOffsetBits; |
| 35 } TypeARM32Attributes[] = { | 38 } TypeARM32Attributes[] = { |
| 36 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ | 39 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ |
| 37 { int_width, vec_width, sbits, ubits } \ | 40 { int_width, vec_width, sbits, ubits } \ |
| 38 , | 41 , |
| 39 ICETYPEARM32_TABLE | 42 ICETYPEARM32_TABLE |
| (...skipping 1264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1304 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { | 1307 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { |
| 1305 assert(getSrcSize() == 1); | 1308 assert(getSrcSize() == 1); |
| 1306 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1309 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1307 Asm->uxt(getDest(), getSrc(0), getPredicate()); | 1310 Asm->uxt(getDest(), getSrc(0), getPredicate()); |
| 1308 if (Asm->needsTextFixup()) | 1311 if (Asm->needsTextFixup()) |
| 1309 emitUsingTextFixup(Func); | 1312 emitUsingTextFixup(Func); |
| 1310 } | 1313 } |
| 1311 | 1314 |
| 1312 namespace { | 1315 namespace { |
| 1313 | 1316 |
| 1314 bool isAssignedConsecutiveRegisters(Variable *Before, Variable *After) { | 1317 bool isAssignedConsecutiveRegisters(const Variable *Before, |
| 1318 const Variable *After) { |
| 1315 assert(Before->hasReg()); | 1319 assert(Before->hasReg()); |
| 1316 assert(After->hasReg()); | 1320 assert(After->hasReg()); |
| 1317 return Before->getRegNum() + 1 == After->getRegNum(); | 1321 return Before->getRegNum() + 1 == After->getRegNum(); |
| 1318 } | 1322 } |
| 1319 | 1323 |
| 1320 } // end of anonymous namespace | 1324 } // end of anonymous namespace |
| 1321 | 1325 |
| 1322 void InstARM32Pop::emit(const Cfg *Func) const { | 1326 void InstARM32Pop::emit(const Cfg *Func) const { |
| 1323 if (!BuildDefs::dump()) | 1327 if (!BuildDefs::dump()) |
| 1324 return; | 1328 return; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 } | 1377 } |
| 1374 Dests[Start]->emit(Func); | 1378 Dests[Start]->emit(Func); |
| 1375 for (SizeT j = Start + 1; j <= End; ++j) { | 1379 for (SizeT j = Start + 1; j <= End; ++j) { |
| 1376 Str << ", "; | 1380 Str << ", "; |
| 1377 Dests[j]->emit(Func); | 1381 Dests[j]->emit(Func); |
| 1378 } | 1382 } |
| 1379 Str << "}"; | 1383 Str << "}"; |
| 1380 } | 1384 } |
| 1381 | 1385 |
| 1382 void InstARM32Pop::emitIAS(const Cfg *Func) const { | 1386 void InstARM32Pop::emitIAS(const Cfg *Func) const { |
| 1383 SizeT IntegerCount = 0; | 1387 // Pop can't be emitted if there are no registers to load. This should never |
| 1384 ARM32::IValueT GPRegisters = 0; | 1388 // happen, but if it does, we don't need to bring Subzero down -- we just skip |
| 1385 const Variable *LastDest = nullptr; | 1389 // emitting the pop instruction (and maybe emit a nop?) The assert() is here |
| 1386 for (const Variable *Var : Dests) { | 1390 // so that we can detect this error during development. |
| 1387 if (!isScalarIntegerType(Var->getType())) | 1391 const SizeT DestSize = Dests.size(); |
| 1388 // TODO(kschimpf) Implement vpush. | 1392 if (DestSize == 0) { |
| 1389 return emitUsingTextFixup(Func); | 1393 assert(false && "Empty pop list"); |
| 1390 assert((Var && Var->hasReg()) && "pop only applies to registers"); | 1394 return; |
| 1391 int32_t Reg = Var->getRegNum(); | |
| 1392 assert(Reg != RegARM32::Encoded_Not_GPR); | |
| 1393 LastDest = Var; | |
| 1394 GPRegisters |= (1 << Reg); | |
| 1395 ++IntegerCount; | |
| 1396 } | 1395 } |
| 1396 |
| 1397 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1397 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1398 switch (IntegerCount) { | 1398 const auto *Reg = llvm::cast<Variable>(Dests[0]); |
| 1399 case 0: | 1399 if (isScalarIntegerType(Reg->getType())) { |
| 1400 return; | 1400 // Pop GPR registers. |
| 1401 case 1: | 1401 SizeT IntegerCount = 0; |
| 1402 // Note: Can only apply pop register if single register is not sp. | 1402 ARM32::IValueT GPRegisters = 0; |
| 1403 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && | 1403 const Variable *LastDest = nullptr; |
| 1404 "Effects of pop register SP is undefined!"); | 1404 for (const Variable *Var : Dests) { |
| 1405 Asm->pop(LastDest, CondARM32::AL); | 1405 assert(Var->hasReg() && "pop only applies to registers"); |
| 1406 break; | 1406 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); |
| 1407 default: | 1407 LastDest = Var; |
| 1408 Asm->popList(GPRegisters, CondARM32::AL); | 1408 GPRegisters |= (1 << Reg); |
| 1409 break; | 1409 ++IntegerCount; |
| 1410 } |
| 1411 switch (IntegerCount) { |
| 1412 case 0: |
| 1413 return; |
| 1414 case 1: |
| 1415 // Note: Can only apply pop register if single register is not sp. |
| 1416 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && |
| 1417 "Effects of pop register SP is undefined!"); |
| 1418 Asm->pop(LastDest, CondARM32::AL); |
| 1419 break; |
| 1420 default: |
| 1421 Asm->popList(GPRegisters, CondARM32::AL); |
| 1422 break; |
| 1423 } |
| 1424 } else { |
| 1425 // Pop vector/floating point registers. |
| 1426 const Variable *BaseReg = nullptr; |
| 1427 SizeT RegCount = 0; |
| 1428 for (const Variable *NextReg : Dests) { |
| 1429 if (BaseReg == nullptr) { |
| 1430 BaseReg = NextReg; |
| 1431 RegCount = 1; |
| 1432 } else if (RegCount < VpushVpopMaxConsecRegs && |
| 1433 isAssignedConsecutiveRegisters(Reg, NextReg)) { |
| 1434 ++RegCount; |
| 1435 } else { |
| 1436 Asm->vpop(BaseReg, RegCount, CondARM32::AL); |
| 1437 BaseReg = NextReg; |
| 1438 RegCount = 1; |
| 1439 } |
| 1440 Reg = NextReg; |
| 1441 } |
| 1442 if (RegCount) |
| 1443 Asm->vpop(BaseReg, RegCount, CondARM32::AL); |
| 1410 } | 1444 } |
| 1411 if (Asm->needsTextFixup()) | 1445 if (Asm->needsTextFixup()) |
| 1412 emitUsingTextFixup(Func); | 1446 emitUsingTextFixup(Func); |
| 1413 } | 1447 } |
| 1414 | 1448 |
| 1415 void InstARM32Pop::dump(const Cfg *Func) const { | 1449 void InstARM32Pop::dump(const Cfg *Func) const { |
| 1416 if (!BuildDefs::dump()) | 1450 if (!BuildDefs::dump()) |
| 1417 return; | 1451 return; |
| 1418 Ostream &Str = Func->getContext()->getStrDump(); | 1452 Ostream &Str = Func->getContext()->getStrDump(); |
| 1419 Str << "pop" | 1453 Str << "pop" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1434 // emitting the push instruction (and maybe emit a nop?) The assert() is here | 1468 // emitting the push instruction (and maybe emit a nop?) The assert() is here |
| 1435 // so that we can detect this error during development. | 1469 // so that we can detect this error during development. |
| 1436 const SizeT SrcSize = getSrcSize(); | 1470 const SizeT SrcSize = getSrcSize(); |
| 1437 if (SrcSize == 0) { | 1471 if (SrcSize == 0) { |
| 1438 assert(false && "Empty push list"); | 1472 assert(false && "Empty push list"); |
| 1439 return; | 1473 return; |
| 1440 } | 1474 } |
| 1441 | 1475 |
| 1442 Ostream &Str = Func->getContext()->getStrEmit(); | 1476 Ostream &Str = Func->getContext()->getStrEmit(); |
| 1443 | 1477 |
| 1444 auto *Reg = llvm::cast<Variable>(getSrc(0)); | 1478 const auto *Reg = llvm::cast<Variable>(getSrc(0)); |
| 1445 if (isScalarIntegerType(Reg->getType())) { | 1479 if (isScalarIntegerType(Reg->getType())) { |
| 1446 // GPR push. | 1480 // GPR push. |
| 1447 Str << "\t" | 1481 Str << "\t" |
| 1448 "push" | 1482 "push" |
| 1449 "\t{"; | 1483 "\t{"; |
| 1450 Reg->emit(Func); | 1484 Reg->emit(Func); |
| 1451 for (SizeT i = 1; i < SrcSize; ++i) { | 1485 for (SizeT i = 1; i < SrcSize; ++i) { |
| 1452 Str << ", "; | 1486 Str << ", "; |
| 1453 getSrc(i)->emit(Func); | 1487 getSrc(i)->emit(Func); |
| 1454 } | 1488 } |
| 1455 Str << "}"; | 1489 Str << "}"; |
| 1456 return; | 1490 return; |
| 1457 } | 1491 } |
| 1458 | 1492 |
| 1459 // VFP "s" reg push. | 1493 // VFP "s" reg push. |
| 1460 Str << "\t" | 1494 Str << "\t" |
| 1461 "vpush" | 1495 "vpush" |
| 1462 "\t{"; | 1496 "\t{"; |
| 1463 Reg->emit(Func); | 1497 Reg->emit(Func); |
| 1498 SizeT RegCount = 1; |
| 1464 for (SizeT i = 1; i < SrcSize; ++i) { | 1499 for (SizeT i = 1; i < SrcSize; ++i) { |
| 1465 auto *NextReg = llvm::cast<Variable>(getSrc(i)); | 1500 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); |
| 1466 if (isAssignedConsecutiveRegisters(Reg, NextReg)) { | 1501 if (RegCount < VpushVpopMaxConsecRegs && |
| 1502 isAssignedConsecutiveRegisters(Reg, NextReg)) { |
| 1503 ++RegCount; |
| 1467 Str << ", "; | 1504 Str << ", "; |
| 1468 } else { | 1505 } else { |
| 1469 startNextInst(Func); | 1506 startNextInst(Func); |
| 1507 RegCount = 1; |
| 1470 Str << "}\n\t" | 1508 Str << "}\n\t" |
| 1471 "vpush" | 1509 "vpush" |
| 1472 "\t{"; | 1510 "\t{"; |
| 1473 } | 1511 } |
| 1474 Reg = NextReg; | 1512 Reg = NextReg; |
| 1475 Reg->emit(Func); | 1513 Reg->emit(Func); |
| 1476 } | 1514 } |
| 1477 Str << "}"; | 1515 Str << "}"; |
| 1478 } | 1516 } |
| 1479 | 1517 |
| 1480 void InstARM32Push::emitIAS(const Cfg *Func) const { | 1518 void InstARM32Push::emitIAS(const Cfg *Func) const { |
| 1481 SizeT IntegerCount = 0; | 1519 // Push can't be emitted if there are no registers to save. This should never |
| 1482 ARM32::IValueT GPRegisters = 0; | 1520 // happen, but if it does, we don't need to bring Subzero down -- we just skip |
| 1483 const Variable *LastSrc = nullptr; | 1521 // emitting the push instruction (and maybe emit a nop?) The assert() is here |
| 1484 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { | 1522 // so that we can detect this error during development. |
| 1485 if (!isScalarIntegerType(getSrc(Index)->getType())) | 1523 const SizeT SrcSize = getSrcSize(); |
| 1486 // TODO(kschimpf) Implement vpush. | 1524 if (SrcSize == 0) { |
| 1487 return emitUsingTextFixup(Func); | 1525 assert(false && "Empty push list"); |
| 1488 const auto *Var = llvm::dyn_cast<Variable>(getSrc(Index)); | 1526 return; |
| 1489 assert((Var && Var->hasReg()) && "push only applies to registers"); | |
| 1490 int32_t Reg = Var->getRegNum(); | |
| 1491 assert(Reg != RegARM32::Encoded_Not_GPR); | |
| 1492 LastSrc = Var; | |
| 1493 GPRegisters |= (1 << Reg); | |
| 1494 ++IntegerCount; | |
| 1495 } | 1527 } |
| 1528 |
| 1496 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1529 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1497 switch (IntegerCount) { | 1530 const auto *Reg = llvm::cast<Variable>(getSrc(0)); |
| 1498 case 0: | 1531 if (isScalarIntegerType(Reg->getType())) { |
| 1499 return; | 1532 // Push GPR registers. |
| 1500 case 1: { | 1533 SizeT IntegerCount = 0; |
| 1501 // Note: Can only apply push register if single register is not sp. | 1534 ARM32::IValueT GPRegisters = 0; |
| 1502 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && | 1535 const Variable *LastSrc = nullptr; |
| 1503 "Effects of push register SP is undefined!"); | 1536 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { |
| 1504 Asm->push(LastSrc, CondARM32::AL); | 1537 const auto *Var = llvm::cast<Variable>(getSrc(Index)); |
| 1505 break; | 1538 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); |
| 1506 } | 1539 assert(Reg != RegARM32::Encoded_Not_GPR); |
| 1507 default: | 1540 LastSrc = Var; |
| 1508 // TODO(kschimpf) Implement pushList in assembler. | 1541 GPRegisters |= (1 << Reg); |
| 1509 Asm->pushList(GPRegisters, CondARM32::AL); | 1542 ++IntegerCount; |
| 1510 break; | 1543 } |
| 1544 switch (IntegerCount) { |
| 1545 case 0: |
| 1546 return; |
| 1547 case 1: { |
| 1548 // Note: Can only apply push register if single register is not sp. |
| 1549 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && |
| 1550 "Effects of push register SP is undefined!"); |
| 1551 Asm->push(LastSrc, CondARM32::AL); |
| 1552 break; |
| 1553 } |
| 1554 default: |
| 1555 Asm->pushList(GPRegisters, CondARM32::AL); |
| 1556 break; |
| 1557 } |
| 1558 } else { |
| 1559 // Push vector/Floating point registers. |
| 1560 const Variable *BaseReg = Reg; |
| 1561 SizeT RegCount = 1; |
| 1562 for (SizeT i = 1; i < SrcSize; ++i) { |
| 1563 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); |
| 1564 if (RegCount < VpushVpopMaxConsecRegs && |
| 1565 isAssignedConsecutiveRegisters(Reg, NextReg)) { |
| 1566 ++RegCount; |
| 1567 } else { |
| 1568 Asm->vpush(BaseReg, RegCount, CondARM32::AL); |
| 1569 BaseReg = NextReg; |
| 1570 RegCount = 1; |
| 1571 } |
| 1572 Reg = NextReg; |
| 1573 } |
| 1574 Asm->vpush(BaseReg, RegCount, CondARM32::AL); |
| 1511 } | 1575 } |
| 1512 if (Asm->needsTextFixup()) | 1576 if (Asm->needsTextFixup()) |
| 1513 emitUsingTextFixup(Func); | 1577 emitUsingTextFixup(Func); |
| 1514 } | 1578 } |
| 1515 | 1579 |
| 1516 void InstARM32Push::dump(const Cfg *Func) const { | 1580 void InstARM32Push::dump(const Cfg *Func) const { |
| 1517 if (!BuildDefs::dump()) | 1581 if (!BuildDefs::dump()) |
| 1518 return; | 1582 return; |
| 1519 Ostream &Str = Func->getContext()->getStrDump(); | 1583 Ostream &Str = Func->getContext()->getStrDump(); |
| 1520 Str << "push" | 1584 Str << "push" |
| (...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2081 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; | 2145 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; |
| 2082 | 2146 |
| 2083 template class InstARM32FourAddrGPR<InstARM32::Mla>; | 2147 template class InstARM32FourAddrGPR<InstARM32::Mla>; |
| 2084 template class InstARM32FourAddrGPR<InstARM32::Mls>; | 2148 template class InstARM32FourAddrGPR<InstARM32::Mls>; |
| 2085 | 2149 |
| 2086 template class InstARM32CmpLike<InstARM32::Cmn>; | 2150 template class InstARM32CmpLike<InstARM32::Cmn>; |
| 2087 template class InstARM32CmpLike<InstARM32::Cmp>; | 2151 template class InstARM32CmpLike<InstARM32::Cmp>; |
| 2088 template class InstARM32CmpLike<InstARM32::Tst>; | 2152 template class InstARM32CmpLike<InstARM32::Tst>; |
| 2089 | 2153 |
| 2090 } // end of namespace Ice | 2154 } // end of namespace Ice |
| OLD | NEW |