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 |
| 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 1248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1288 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { | 1291 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { |
| 1289 assert(getSrcSize() == 1); | 1292 assert(getSrcSize() == 1); |
| 1290 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1293 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1291 Asm->uxt(getDest(), getSrc(0), getPredicate()); | 1294 Asm->uxt(getDest(), getSrc(0), getPredicate()); |
| 1292 if (Asm->needsTextFixup()) | 1295 if (Asm->needsTextFixup()) |
| 1293 emitUsingTextFixup(Func); | 1296 emitUsingTextFixup(Func); |
| 1294 } | 1297 } |
| 1295 | 1298 |
| 1296 namespace { | 1299 namespace { |
| 1297 | 1300 |
| 1298 bool isAssignedConsecutiveRegisters(Variable *Before, Variable *After) { | 1301 bool isAssignedConsecutiveRegisters(const Variable *Before, |
| 1302 const Variable *After) { | |
| 1299 assert(Before->hasReg()); | 1303 assert(Before->hasReg()); |
| 1300 assert(After->hasReg()); | 1304 assert(After->hasReg()); |
| 1301 return Before->getRegNum() + 1 == After->getRegNum(); | 1305 return Before->getRegNum() + 1 == After->getRegNum(); |
| 1302 } | 1306 } |
| 1303 | 1307 |
| 1304 } // end of anonymous namespace | 1308 } // end of anonymous namespace |
| 1305 | 1309 |
| 1306 void InstARM32Pop::emit(const Cfg *Func) const { | 1310 void InstARM32Pop::emit(const Cfg *Func) const { |
| 1307 if (!BuildDefs::dump()) | 1311 if (!BuildDefs::dump()) |
| 1308 return; | 1312 return; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1357 } | 1361 } |
| 1358 Dests[Start]->emit(Func); | 1362 Dests[Start]->emit(Func); |
| 1359 for (SizeT j = Start + 1; j <= End; ++j) { | 1363 for (SizeT j = Start + 1; j <= End; ++j) { |
| 1360 Str << ", "; | 1364 Str << ", "; |
| 1361 Dests[j]->emit(Func); | 1365 Dests[j]->emit(Func); |
| 1362 } | 1366 } |
| 1363 Str << "}"; | 1367 Str << "}"; |
| 1364 } | 1368 } |
| 1365 | 1369 |
| 1366 void InstARM32Pop::emitIAS(const Cfg *Func) const { | 1370 void InstARM32Pop::emitIAS(const Cfg *Func) const { |
| 1367 SizeT IntegerCount = 0; | 1371 // Pop can't be emitted if there are no registers to load. This should never |
| 1368 ARM32::IValueT GPRegisters = 0; | 1372 // happen, but if it does, we don't need to bring Subzero down -- we just skip |
| 1369 const Variable *LastDest = nullptr; | 1373 // emitting the pop instruction (and maybe emit a nop?) The assert() is here |
| 1370 for (const Variable *Var : Dests) { | 1374 // so that we can detect this error during development. |
| 1371 if (!isScalarIntegerType(Var->getType())) | 1375 const SizeT DestSize = Dests.size(); |
| 1372 // TODO(kschimpf) Implement vpush. | 1376 if (DestSize == 0) { |
| 1373 return emitUsingTextFixup(Func); | 1377 assert(false && "Empty pop list"); |
| 1374 assert((Var && Var->hasReg()) && "pop only applies to registers"); | 1378 return; |
| 1375 int32_t Reg = Var->getRegNum(); | |
| 1376 assert(Reg != RegARM32::Encoded_Not_GPR); | |
| 1377 LastDest = Var; | |
| 1378 GPRegisters |= (1 << Reg); | |
| 1379 ++IntegerCount; | |
| 1380 } | 1379 } |
| 1380 | |
| 1381 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1381 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1382 switch (IntegerCount) { | 1382 const auto *Reg = llvm::cast<Variable>(Dests[0]); |
| 1383 case 0: | 1383 if (isScalarIntegerType(Reg->getType())) { |
| 1384 return; | 1384 // Pop GPR registers. |
| 1385 case 1: | 1385 SizeT IntegerCount = 0; |
| 1386 // Note: Can only apply pop register if single register is not sp. | 1386 ARM32::IValueT GPRegisters = 0; |
| 1387 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && | 1387 const Variable *LastDest = nullptr; |
| 1388 "Effects of pop register SP is undefined!"); | 1388 for (const Variable *Var : Dests) { |
| 1389 Asm->pop(LastDest, CondARM32::AL); | 1389 assert((Var && Var->hasReg()) && "pop only applies to registers"); |
|
Jim Stichnoth
2015/12/18 00:03:11
I think you can assume Var!=nullptr, and remove th
Karl
2015/12/18 16:26:50
Done.
| |
| 1390 break; | 1390 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); |
| 1391 default: | 1391 LastDest = Var; |
| 1392 Asm->popList(GPRegisters, CondARM32::AL); | 1392 GPRegisters |= (1 << Reg); |
| 1393 break; | 1393 ++IntegerCount; |
| 1394 } | |
| 1395 switch (IntegerCount) { | |
| 1396 case 0: | |
| 1397 return; | |
| 1398 case 1: | |
| 1399 // Note: Can only apply pop register if single register is not sp. | |
| 1400 assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) && | |
| 1401 "Effects of pop register SP is undefined!"); | |
| 1402 Asm->pop(LastDest, CondARM32::AL); | |
| 1403 break; | |
| 1404 default: | |
| 1405 Asm->popList(GPRegisters, CondARM32::AL); | |
| 1406 break; | |
| 1407 } | |
| 1408 } else { | |
| 1409 // Pop vector/floating point registers. | |
| 1410 const Variable *BaseReg = nullptr; | |
| 1411 SizeT RegCount = 0; | |
| 1412 for (const Variable *NextReg : Dests) { | |
| 1413 if (BaseReg == nullptr) { | |
| 1414 BaseReg = NextReg; | |
| 1415 RegCount = 1; | |
| 1416 } else if (RegCount < VpushVpopMaxConsecRegs && | |
| 1417 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1418 ++RegCount; | |
| 1419 } else { | |
| 1420 Asm->vpop(BaseReg, RegCount, CondARM32::AL); | |
| 1421 BaseReg = NextReg; | |
| 1422 RegCount = 1; | |
| 1423 } | |
| 1424 Reg = NextReg; | |
| 1425 } | |
| 1426 if (RegCount) | |
| 1427 Asm->vpop(BaseReg, RegCount, CondARM32::AL); | |
| 1394 } | 1428 } |
| 1395 if (Asm->needsTextFixup()) | 1429 if (Asm->needsTextFixup()) |
| 1396 emitUsingTextFixup(Func); | 1430 emitUsingTextFixup(Func); |
| 1397 } | 1431 } |
| 1398 | 1432 |
| 1399 void InstARM32Pop::dump(const Cfg *Func) const { | 1433 void InstARM32Pop::dump(const Cfg *Func) const { |
| 1400 if (!BuildDefs::dump()) | 1434 if (!BuildDefs::dump()) |
| 1401 return; | 1435 return; |
| 1402 Ostream &Str = Func->getContext()->getStrDump(); | 1436 Ostream &Str = Func->getContext()->getStrDump(); |
| 1403 Str << "pop" | 1437 Str << "pop" |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1418 // emitting the push instruction (and maybe emit a nop?) The assert() is here | 1452 // emitting the push instruction (and maybe emit a nop?) The assert() is here |
| 1419 // so that we can detect this error during development. | 1453 // so that we can detect this error during development. |
| 1420 const SizeT SrcSize = getSrcSize(); | 1454 const SizeT SrcSize = getSrcSize(); |
| 1421 if (SrcSize == 0) { | 1455 if (SrcSize == 0) { |
| 1422 assert(false && "Empty push list"); | 1456 assert(false && "Empty push list"); |
| 1423 return; | 1457 return; |
| 1424 } | 1458 } |
| 1425 | 1459 |
| 1426 Ostream &Str = Func->getContext()->getStrEmit(); | 1460 Ostream &Str = Func->getContext()->getStrEmit(); |
| 1427 | 1461 |
| 1428 auto *Reg = llvm::cast<Variable>(getSrc(0)); | 1462 const auto *Reg = llvm::cast<Variable>(getSrc(0)); |
| 1429 if (isScalarIntegerType(Reg->getType())) { | 1463 if (isScalarIntegerType(Reg->getType())) { |
| 1430 // GPR push. | 1464 // GPR push. |
| 1431 Str << "\t" | 1465 Str << "\t" |
| 1432 "push" | 1466 "push" |
| 1433 "\t{"; | 1467 "\t{"; |
| 1434 Reg->emit(Func); | 1468 Reg->emit(Func); |
| 1435 for (SizeT i = 1; i < SrcSize; ++i) { | 1469 for (SizeT i = 1; i < SrcSize; ++i) { |
| 1436 Str << ", "; | 1470 Str << ", "; |
| 1437 getSrc(i)->emit(Func); | 1471 getSrc(i)->emit(Func); |
| 1438 } | 1472 } |
| 1439 Str << "}"; | 1473 Str << "}"; |
| 1440 return; | 1474 return; |
| 1441 } | 1475 } |
| 1442 | 1476 |
| 1443 // VFP "s" reg push. | 1477 // VFP "s" reg push. |
| 1444 Str << "\t" | 1478 Str << "\t" |
| 1445 "vpush" | 1479 "vpush" |
| 1446 "\t{"; | 1480 "\t{"; |
| 1447 Reg->emit(Func); | 1481 Reg->emit(Func); |
| 1482 SizeT RegCount = 1; | |
| 1448 for (SizeT i = 1; i < SrcSize; ++i) { | 1483 for (SizeT i = 1; i < SrcSize; ++i) { |
| 1449 auto *NextReg = llvm::cast<Variable>(getSrc(i)); | 1484 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); |
| 1450 if (isAssignedConsecutiveRegisters(Reg, NextReg)) { | 1485 if (RegCount < VpushVpopMaxConsecRegs && |
| 1486 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1487 ++RegCount; | |
| 1451 Str << ", "; | 1488 Str << ", "; |
| 1452 } else { | 1489 } else { |
| 1453 startNextInst(Func); | 1490 startNextInst(Func); |
| 1491 RegCount = 1; | |
| 1454 Str << "}\n\t" | 1492 Str << "}\n\t" |
| 1455 "vpush" | 1493 "vpush" |
| 1456 "\t{"; | 1494 "\t{"; |
| 1457 } | 1495 } |
| 1458 Reg = NextReg; | 1496 Reg = NextReg; |
| 1459 Reg->emit(Func); | 1497 Reg->emit(Func); |
| 1460 } | 1498 } |
| 1461 Str << "}"; | 1499 Str << "}"; |
| 1462 } | 1500 } |
| 1463 | 1501 |
| 1464 void InstARM32Push::emitIAS(const Cfg *Func) const { | 1502 void InstARM32Push::emitIAS(const Cfg *Func) const { |
| 1465 SizeT IntegerCount = 0; | 1503 // Push can't be emitted if there are no registers to save. This should never |
| 1466 ARM32::IValueT GPRegisters = 0; | 1504 // happen, but if it does, we don't need to bring Subzero down -- we just skip |
| 1467 const Variable *LastSrc = nullptr; | 1505 // emitting the push instruction (and maybe emit a nop?) The assert() is here |
| 1468 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { | 1506 // so that we can detect this error during development. |
| 1469 if (!isScalarIntegerType(getSrc(Index)->getType())) | 1507 const SizeT SrcSize = getSrcSize(); |
| 1470 // TODO(kschimpf) Implement vpush. | 1508 if (SrcSize == 0) { |
| 1471 return emitUsingTextFixup(Func); | 1509 assert(false && "Empty push list"); |
| 1472 const auto *Var = llvm::dyn_cast<Variable>(getSrc(Index)); | 1510 return; |
| 1473 assert((Var && Var->hasReg()) && "push only applies to registers"); | |
| 1474 int32_t Reg = Var->getRegNum(); | |
| 1475 assert(Reg != RegARM32::Encoded_Not_GPR); | |
| 1476 LastSrc = Var; | |
| 1477 GPRegisters |= (1 << Reg); | |
| 1478 ++IntegerCount; | |
| 1479 } | 1511 } |
| 1512 | |
| 1480 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); | 1513 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 1481 switch (IntegerCount) { | 1514 const auto *Reg = llvm::cast<Variable>(getSrc(0)); |
| 1482 case 0: | 1515 if (isScalarIntegerType(Reg->getType())) { |
| 1483 return; | 1516 // Push GPR registers. |
| 1484 case 1: { | 1517 SizeT IntegerCount = 0; |
| 1485 // Note: Can only apply push register if single register is not sp. | 1518 ARM32::IValueT GPRegisters = 0; |
| 1486 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && | 1519 const Variable *LastSrc = nullptr; |
| 1487 "Effects of push register SP is undefined!"); | 1520 for (SizeT Index = 0; Index < getSrcSize(); ++Index) { |
| 1488 Asm->push(LastSrc, CondARM32::AL); | 1521 const auto *Var = llvm::cast<Variable>(getSrc(Index)); |
| 1489 break; | 1522 int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); |
| 1490 } | 1523 assert(Reg != RegARM32::Encoded_Not_GPR); |
| 1491 default: | 1524 LastSrc = Var; |
| 1492 // TODO(kschimpf) Implement pushList in assembler. | 1525 GPRegisters |= (1 << Reg); |
| 1493 Asm->pushList(GPRegisters, CondARM32::AL); | 1526 ++IntegerCount; |
| 1494 break; | 1527 } |
| 1528 switch (IntegerCount) { | |
| 1529 case 0: | |
| 1530 return; | |
| 1531 case 1: { | |
| 1532 // Note: Can only apply push register if single register is not sp. | |
| 1533 assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) && | |
| 1534 "Effects of push register SP is undefined!"); | |
| 1535 Asm->push(LastSrc, CondARM32::AL); | |
| 1536 break; | |
| 1537 } | |
| 1538 default: | |
| 1539 Asm->pushList(GPRegisters, CondARM32::AL); | |
| 1540 break; | |
| 1541 } | |
| 1542 } else { | |
| 1543 // Push vector/Floating point registers. | |
| 1544 const Variable *BaseReg = Reg; | |
| 1545 SizeT RegCount = 1; | |
| 1546 for (SizeT i = 1; i < SrcSize; ++i) { | |
| 1547 const auto *NextReg = llvm::cast<Variable>(getSrc(i)); | |
| 1548 if (RegCount < VpushVpopMaxConsecRegs && | |
| 1549 isAssignedConsecutiveRegisters(Reg, NextReg)) { | |
| 1550 ++RegCount; | |
| 1551 } else { | |
| 1552 Asm->vpush(BaseReg, RegCount, CondARM32::AL); | |
| 1553 BaseReg = NextReg; | |
| 1554 RegCount = 1; | |
| 1555 } | |
| 1556 Reg = NextReg; | |
| 1557 } | |
| 1558 Asm->vpush(BaseReg, RegCount, CondARM32::AL); | |
| 1495 } | 1559 } |
| 1496 if (Asm->needsTextFixup()) | 1560 if (Asm->needsTextFixup()) |
| 1497 emitUsingTextFixup(Func); | 1561 emitUsingTextFixup(Func); |
| 1498 } | 1562 } |
| 1499 | 1563 |
| 1500 void InstARM32Push::dump(const Cfg *Func) const { | 1564 void InstARM32Push::dump(const Cfg *Func) const { |
| 1501 if (!BuildDefs::dump()) | 1565 if (!BuildDefs::dump()) |
| 1502 return; | 1566 return; |
| 1503 Ostream &Str = Func->getContext()->getStrDump(); | 1567 Ostream &Str = Func->getContext()->getStrDump(); |
| 1504 Str << "push" | 1568 Str << "push" |
| (...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2065 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; | 2129 template class InstARM32UnaryopFP<InstARM32::Vsqrt>; |
| 2066 | 2130 |
| 2067 template class InstARM32FourAddrGPR<InstARM32::Mla>; | 2131 template class InstARM32FourAddrGPR<InstARM32::Mla>; |
| 2068 template class InstARM32FourAddrGPR<InstARM32::Mls>; | 2132 template class InstARM32FourAddrGPR<InstARM32::Mls>; |
| 2069 | 2133 |
| 2070 template class InstARM32CmpLike<InstARM32::Cmn>; | 2134 template class InstARM32CmpLike<InstARM32::Cmn>; |
| 2071 template class InstARM32CmpLike<InstARM32::Cmp>; | 2135 template class InstARM32CmpLike<InstARM32::Cmp>; |
| 2072 template class InstARM32CmpLike<InstARM32::Tst>; | 2136 template class InstARM32CmpLike<InstARM32::Tst>; |
| 2073 | 2137 |
| 2074 } // end of namespace Ice | 2138 } // end of namespace Ice |
| OLD | NEW |