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 |