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

Side by Side Diff: src/IceTargetLoweringARM32.cpp

Issue 1477873002: Subzero. ARM32. Folding rematerializable offsets in address operands. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: make format Created 5 years 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
« no previous file with comments | « src/IceTargetLoweringARM32.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===//
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 663 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 } 674 }
675 675
676 ForbidTemporaryWithoutReg _(this); 676 ForbidTemporaryWithoutReg _(this);
677 677
678 // Stack frame mapping. 678 // Stack frame mapping.
679 Func->genFrame(); 679 Func->genFrame();
680 if (Func->hasError()) 680 if (Func->hasError())
681 return; 681 return;
682 Func->dump("After stack frame mapping"); 682 Func->dump("After stack frame mapping");
683 683
684 legalizeStackSlots(); 684 postLowerLegalization();
685 if (Func->hasError()) 685 if (Func->hasError())
686 return; 686 return;
687 Func->dump("After legalizeStackSlots"); 687 Func->dump("After postLowerLegalization");
688 688
689 Func->contractEmptyNodes(); 689 Func->contractEmptyNodes();
690 Func->reorderNodes(); 690 Func->reorderNodes();
691 691
692 // Branch optimization. This needs to be done just before code emission. In 692 // Branch optimization. This needs to be done just before code emission. In
693 // particular, no transformations that insert or reorder CfgNodes should be 693 // particular, no transformations that insert or reorder CfgNodes should be
694 // done after branch optimization. We go ahead and do it before nop insertion 694 // done after branch optimization. We go ahead and do it before nop insertion
695 // to reduce the amount of work needed for searching for opportunities. 695 // to reduce the amount of work needed for searching for opportunities.
696 Func->doBranchOpt(); 696 Func->doBranchOpt();
697 Func->dump("After branch optimization"); 697 Func->dump("After branch optimization");
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
739 copyRegAllocFromInfWeightVariable64On32(Func->getVariables()); 739 copyRegAllocFromInfWeightVariable64On32(Func->getVariables());
740 Func->dump("After regalloc of infinite-weight variables"); 740 Func->dump("After regalloc of infinite-weight variables");
741 741
742 ForbidTemporaryWithoutReg _(this); 742 ForbidTemporaryWithoutReg _(this);
743 743
744 Func->genFrame(); 744 Func->genFrame();
745 if (Func->hasError()) 745 if (Func->hasError())
746 return; 746 return;
747 Func->dump("After stack frame mapping"); 747 Func->dump("After stack frame mapping");
748 748
749 legalizeStackSlots(); 749 postLowerLegalization();
750 if (Func->hasError()) 750 if (Func->hasError())
751 return; 751 return;
752 Func->dump("After legalizeStackSlots"); 752 Func->dump("After postLowerLegalization");
753 753
754 // Nop insertion 754 // Nop insertion
755 if (Ctx->getFlags().shouldDoNopInsertion()) { 755 if (Ctx->getFlags().shouldDoNopInsertion()) {
756 Func->doNopInsertion(); 756 Func->doNopInsertion();
757 } 757 }
758 } 758 }
759 759
760 uint32_t TargetARM32::getStackAlignment() const { 760 uint32_t TargetARM32::getStackAlignment() const {
761 return ARM32_STACK_ALIGNMENT_BYTES; 761 return ARM32_STACK_ALIGNMENT_BYTES;
762 } 762 }
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
1329 _ret(LR, RetValue); 1329 _ret(LR, RetValue);
1330 _bundle_unlock(); 1330 _bundle_unlock();
1331 RI->setDeleted(); 1331 RI->setDeleted();
1332 } 1332 }
1333 1333
1334 bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const { 1334 bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const {
1335 constexpr bool ZeroExt = false; 1335 constexpr bool ZeroExt = false;
1336 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset); 1336 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset);
1337 } 1337 }
1338 1338
1339 Variable *TargetARM32::newBaseRegister(int32_t Offset, Variable *OrigBaseReg) { 1339 Variable *TargetARM32::PostLoweringLegalizer::newBaseRegister(
1340 Variable *Base, int32_t Offset, int32_t ScratchRegNum) {
1340 // Legalize will likely need a movw/movt combination, but if the top bits are 1341 // Legalize will likely need a movw/movt combination, but if the top bits are
1341 // all 0 from negating the offset and subtracting, we could use that instead. 1342 // all 0 from negating the offset and subtracting, we could use that instead.
1342 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; 1343 const bool ShouldSub = Offset != 0 && (-Offset & 0xFFFF0000) == 0;
1343 if (ShouldSub) 1344 Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum);
1344 Offset = -Offset; 1345 if (ShouldSub) {
1345 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset), 1346 Operand *OffsetVal =
1346 Legal_Reg | Legal_Flex, getReservedTmpReg()); 1347 Target->legalize(Target->Ctx->getConstantInt32(-Offset),
1347 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg()); 1348 Legal_Reg | Legal_Flex, ScratchRegNum);
1348 if (ShouldSub) 1349 Target->_sub(ScratchReg, Base, OffsetVal);
1349 _sub(ScratchReg, OrigBaseReg, OffsetVal); 1350 } else {
1350 else 1351 Operand *OffsetVal =
1351 _add(ScratchReg, OrigBaseReg, OffsetVal); 1352 Target->legalize(Target->Ctx->getConstantInt32(Offset),
1353 Legal_Reg | Legal_Flex, ScratchRegNum);
1354 Target->_add(ScratchReg, Base, OffsetVal);
1355 }
1356
1357 if (ScratchRegNum == Target->getReservedTmpReg()) {
1358 const bool BaseIsStackOrFramePtr =
1359 Base->getRegNum() == static_cast<int32_t>(Target->getFrameOrStackReg());
1360 // There is currently no code path that would trigger this assertion, so we
1361 // leave this assertion here in case it is ever violated. This is not a
1362 // fatal error (thus the use of assert() and not llvm::report_fatal_error)
1363 // as the program compiled by subzero will still work correctly.
1364 assert(BaseIsStackOrFramePtr);
1365 // Side-effect: updates TempBase to reflect the new Temporary.
1366 if (BaseIsStackOrFramePtr) {
1367 TempBaseReg = ScratchReg;
1368 TempBaseOffset = Offset;
1369 } else {
1370 TempBaseReg = nullptr;
1371 TempBaseOffset = 0;
1372 }
1373 }
1374
1352 return ScratchReg; 1375 return ScratchReg;
1353 } 1376 }
1354 1377
1355 OperandARM32Mem *TargetARM32::createMemOperand(Type Ty, int32_t Offset, 1378 OperandARM32Mem *TargetARM32::PostLoweringLegalizer::createMemOperand(
1356 Variable *OrigBaseReg, 1379 Type Ty, Variable *Base, int32_t Offset, bool AllowOffsets) {
1357 Variable **NewBaseReg, 1380 assert(!Base->isRematerializable());
1358 int32_t *NewBaseOffset) { 1381 if (AllowOffsets && Target->isLegalMemOffset(Ty, Offset)) {
1359 assert(!OrigBaseReg->isRematerializable());
1360 if (isLegalMemOffset(Ty, Offset)) {
1361 return OperandARM32Mem::create( 1382 return OperandARM32Mem::create(
1362 Func, Ty, OrigBaseReg, 1383 Target->Func, Ty, Base,
1363 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(Offset)), 1384 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)),
1364 OperandARM32Mem::Offset); 1385 OperandARM32Mem::Offset);
1365 } 1386 }
1366 1387
1367 if (*NewBaseReg == nullptr) { 1388 if (!AllowOffsets || TempBaseReg == nullptr) {
1368 *NewBaseReg = newBaseRegister(Offset, OrigBaseReg); 1389 newBaseRegister(Base, Offset, Target->getReservedTmpReg());
1369 *NewBaseOffset = Offset;
1370 } 1390 }
1371 1391
1372 int32_t OffsetDiff = Offset - *NewBaseOffset; 1392 int32_t OffsetDiff = Offset - TempBaseOffset;
1373 if (!isLegalMemOffset(Ty, OffsetDiff)) { 1393 assert(AllowOffsets || OffsetDiff == 0);
1374 *NewBaseReg = newBaseRegister(Offset, OrigBaseReg); 1394
1375 *NewBaseOffset = Offset; 1395 if (!Target->isLegalMemOffset(Ty, OffsetDiff)) {
1396 newBaseRegister(Base, Offset, Target->getReservedTmpReg());
1376 OffsetDiff = 0; 1397 OffsetDiff = 0;
1377 } 1398 }
1378 1399
1379 assert(!(*NewBaseReg)->isRematerializable()); 1400 assert(!TempBaseReg->isRematerializable());
1380 return OperandARM32Mem::create( 1401 return OperandARM32Mem::create(
1381 Func, Ty, *NewBaseReg, 1402 Target->Func, Ty, TempBaseReg,
1382 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetDiff)), 1403 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(OffsetDiff)),
1383 OperandARM32Mem::Offset); 1404 OperandARM32Mem::Offset);
1384 } 1405 }
1385 1406
1386 void TargetARM32::legalizeMov(InstARM32Mov *MovInstr, Variable *OrigBaseReg, 1407 void TargetARM32::PostLoweringLegalizer::resetTempBaseIfClobberedBy(
1387 Variable **NewBaseReg, int32_t *NewBaseOffset) { 1408 const Inst *Instr) {
1409 bool ClobbersTempBase = false;
1410 if (TempBaseReg != nullptr) {
1411 Variable *Dest = Instr->getDest();
1412 if (llvm::isa<InstARM32Call>(Instr)) {
1413 // The following assertion is an invariant, so we remove it from the if
1414 // test. If the invariant is ever broken/invalidated/changed, remember
1415 // to add it back to the if condition.
1416 assert(TempBaseReg->getRegNum() == Target->getReservedTmpReg());
1417 // The linker may need to clobber IP if the call is too far from PC. Thus,
1418 // we assume IP will be overwritten.
1419 ClobbersTempBase = true;
1420 } else if (Dest != nullptr &&
1421 Dest->getRegNum() == TempBaseReg->getRegNum()) {
1422 // Register redefinition.
1423 ClobbersTempBase = true;
1424 }
1425 }
1426
1427 if (ClobbersTempBase) {
1428 TempBaseReg = nullptr;
1429 TempBaseOffset = 0;
1430 }
1431 }
1432
1433 void TargetARM32::PostLoweringLegalizer::legalizeMov(InstARM32Mov *MovInstr) {
1388 Variable *Dest = MovInstr->getDest(); 1434 Variable *Dest = MovInstr->getDest();
1389 assert(Dest != nullptr); 1435 assert(Dest != nullptr);
1390 Type DestTy = Dest->getType(); 1436 Type DestTy = Dest->getType();
1391 assert(DestTy != IceType_i64); 1437 assert(DestTy != IceType_i64);
1392 1438
1393 Operand *Src = MovInstr->getSrc(0); 1439 Operand *Src = MovInstr->getSrc(0);
1394 Type SrcTy = Src->getType(); 1440 Type SrcTy = Src->getType();
1395 (void)SrcTy; 1441 (void)SrcTy;
1396 assert(SrcTy != IceType_i64); 1442 assert(SrcTy != IceType_i64);
1397 1443
1398 if (MovInstr->isMultiDest() || MovInstr->isMultiSource()) 1444 if (MovInstr->isMultiDest() || MovInstr->isMultiSource())
1399 return; 1445 return;
1400 1446
1401 bool Legalized = false; 1447 bool Legalized = false;
1402 if (!Dest->hasReg()) { 1448 if (!Dest->hasReg()) {
1403 auto *SrcR = llvm::cast<Variable>(Src); 1449 auto *SrcR = llvm::cast<Variable>(Src);
1404 assert(SrcR->hasReg()); 1450 assert(SrcR->hasReg());
1405 assert(!SrcR->isRematerializable()); 1451 assert(!SrcR->isRematerializable());
1406 const int32_t Offset = Dest->getStackOffset(); 1452 const int32_t Offset = Dest->getStackOffset();
1407 // This is a _mov(Mem(), Variable), i.e., a store. 1453 // This is a _mov(Mem(), Variable), i.e., a store.
1408 _str(SrcR, createMemOperand(DestTy, Offset, OrigBaseReg, NewBaseReg, 1454 Target->_str(SrcR, createMemOperand(DestTy, StackOrFrameReg, Offset),
1409 NewBaseOffset), 1455 MovInstr->getPredicate());
1410 MovInstr->getPredicate());
1411 // _str() does not have a Dest, so we add a fake-def(Dest). 1456 // _str() does not have a Dest, so we add a fake-def(Dest).
1412 Context.insert(InstFakeDef::create(Func, Dest)); 1457 Target->Context.insert(InstFakeDef::create(Target->Func, Dest));
1413 Legalized = true; 1458 Legalized = true;
1414 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) { 1459 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) {
1415 if (Var->isRematerializable()) { 1460 if (Var->isRematerializable()) {
1416 // Rematerialization arithmetic. 1461 // This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable).
1462
1463 // ExtraOffset is only needed for frame-pointer based frames as we have
1464 // to account for spill storage.
1417 const int32_t ExtraOffset = 1465 const int32_t ExtraOffset =
1418 (static_cast<SizeT>(Var->getRegNum()) == getFrameReg()) 1466 (static_cast<SizeT>(Var->getRegNum()) == Target->getFrameReg())
1419 ? getFrameFixedAllocaOffset() 1467 ? Target->getFrameFixedAllocaOffset()
1420 : 0; 1468 : 0;
1421 1469
1422 const int32_t Offset = Var->getStackOffset() + ExtraOffset; 1470 const int32_t Offset = Var->getStackOffset() + ExtraOffset;
1423 Operand *OffsetRF = legalize(Ctx->getConstantInt32(Offset), 1471 Variable *Base = Target->getPhysicalRegister(Var->getRegNum());
1424 Legal_Reg | Legal_Flex, Dest->getRegNum()); 1472 Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum());
1425 _add(Dest, Var, OffsetRF); 1473 Target->_mov(Dest, T);
1426 Legalized = true; 1474 Legalized = true;
1427 } else { 1475 } else {
1428 if (!Var->hasReg()) { 1476 if (!Var->hasReg()) {
1477 // This is a _mov(Variable, Mem()), i.e., a load.
1429 const int32_t Offset = Var->getStackOffset(); 1478 const int32_t Offset = Var->getStackOffset();
1430 _ldr(Dest, createMemOperand(DestTy, Offset, OrigBaseReg, NewBaseReg, 1479 Target->_ldr(Dest, createMemOperand(DestTy, StackOrFrameReg, Offset),
1431 NewBaseOffset), 1480 MovInstr->getPredicate());
1432 MovInstr->getPredicate());
1433 Legalized = true; 1481 Legalized = true;
1434 } 1482 }
1435 } 1483 }
1436 } 1484 }
1437 1485
1438 if (Legalized) { 1486 if (Legalized) {
1439 if (MovInstr->isDestRedefined()) { 1487 if (MovInstr->isDestRedefined()) {
1440 _set_dest_redefined(); 1488 Target->_set_dest_redefined();
1441 } 1489 }
1442 MovInstr->setDeleted(); 1490 MovInstr->setDeleted();
1443 } 1491 }
1444 } 1492 }
1445 1493
1446 void TargetARM32::legalizeStackSlots() { 1494 // ARM32 address modes:
1495 // ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12],
1496 // [reg +/- reg << shamt5]
1497 // ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8]
1498 // ld/st vectors : [reg]
1499 //
1500 // For now, we don't handle address modes with Relocatables.
1501 namespace {
1502 // MemTraits contains per-type valid address mode information.
1503 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \
1504 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag);
1505 ICETYPEARM32_TABLE
1506 #undef X
1507
1508 static const struct {
1509 int32_t ValidImmMask;
1510 bool CanHaveImm;
1511 bool CanHaveIndex;
1512 bool CanHaveShiftedIndex;
1513 } MemTraits[] = {
1514 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \
1515 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \
1516 ,
1517 ICETYPEARM32_TABLE
1518 #undef X
1519 };
1520 static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits);
1521 } // end of anonymous namespace
1522
1523 OperandARM32Mem *
1524 TargetARM32::PostLoweringLegalizer::legalizeMemOperand(OperandARM32Mem *Mem,
1525 bool AllowOffsets) {
1526 assert(!Mem->isRegReg() || !Mem->getIndex()->isRematerializable());
1527 assert(
1528 Mem->isRegReg() ||
1529 Target->isLegalMemOffset(Mem->getType(), Mem->getOffset()->getValue()));
1530
1531 bool Legalized = false;
1532 Variable *Base = Mem->getBase();
1533 int32_t Offset = Mem->isRegReg() ? 0 : Mem->getOffset()->getValue();
1534 if (Base->isRematerializable()) {
1535 const int32_t ExtraOffset =
1536 (static_cast<SizeT>(Base->getRegNum()) == Target->getFrameReg())
1537 ? Target->getFrameFixedAllocaOffset()
1538 : 0;
1539 Offset += Base->getStackOffset() + ExtraOffset;
1540 Base = Target->getPhysicalRegister(Base->getRegNum());
1541 assert(!Base->isRematerializable());
1542 Legalized = true;
1543 }
1544
1545 if (!Legalized) {
1546 return nullptr;
1547 }
1548
1549 if (!Mem->isRegReg()) {
1550 return createMemOperand(Mem->getType(), Base, Offset, AllowOffsets);
1551 }
1552
1553 assert(MemTraits[Mem->getType()].CanHaveIndex);
1554
1555 if (Offset != 0) {
1556 if (TempBaseReg == nullptr) {
1557 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
1558 } else {
1559 uint32_t Imm8, Rotate;
1560 const int32_t OffsetDiff = Offset - TempBaseOffset;
1561 if (OffsetDiff == 0) {
1562 Base = TempBaseReg;
1563 } else if (OperandARM32FlexImm::canHoldImm(OffsetDiff, &Rotate, &Imm8)) {
1564 auto *OffsetDiffF = OperandARM32FlexImm::create(
1565 Target->Func, IceType_i32, Imm8, Rotate);
1566 Target->_add(TempBaseReg, TempBaseReg, OffsetDiffF);
1567 TempBaseOffset += OffsetDiff;
1568 Base = TempBaseReg;
1569 } else if (OperandARM32FlexImm::canHoldImm(-OffsetDiff, &Rotate, &Imm8)) {
1570 auto *OffsetDiffF = OperandARM32FlexImm::create(
1571 Target->Func, IceType_i32, Imm8, Rotate);
1572 Target->_sub(TempBaseReg, TempBaseReg, OffsetDiffF);
1573 TempBaseOffset += OffsetDiff;
1574 Base = TempBaseReg;
1575 } else {
1576 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
1577 }
1578 }
1579 }
1580
1581 return OperandARM32Mem::create(Target->Func, Mem->getType(), Base,
1582 Mem->getIndex(), Mem->getShiftOp(),
1583 Mem->getShiftAmt(), Mem->getAddrMode());
1584 }
1585
1586 void TargetARM32::postLowerLegalization() {
1447 // If a stack variable's frame offset doesn't fit, convert from: 1587 // If a stack variable's frame offset doesn't fit, convert from:
1448 // ldr X, OFF[SP] 1588 // ldr X, OFF[SP]
1449 // to: 1589 // to:
1450 // movw/movt TMP, OFF_PART 1590 // movw/movt TMP, OFF_PART
1451 // add TMP, TMP, SP 1591 // add TMP, TMP, SP
1452 // ldr X, OFF_MORE[TMP] 1592 // ldr X, OFF_MORE[TMP]
1453 // 1593 //
1454 // This is safe because we have reserved TMP, and add for ARM does not 1594 // This is safe because we have reserved TMP, and add for ARM does not
1455 // clobber the flags register. 1595 // clobber the flags register.
1456 Func->dump("Before legalizeStackSlots"); 1596 Func->dump("Before postLowerLegalization");
1457 assert(hasComputedFrame()); 1597 assert(hasComputedFrame());
1458 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg());
1459 // Do a fairly naive greedy clustering for now. Pick the first stack slot 1598 // Do a fairly naive greedy clustering for now. Pick the first stack slot
1460 // that's out of bounds and make a new base reg using the architecture's temp 1599 // that's out of bounds and make a new base reg using the architecture's temp
1461 // register. If that works for the next slot, then great. Otherwise, create a 1600 // register. If that works for the next slot, then great. Otherwise, create a
1462 // new base register, clobbering the previous base register. Never share a 1601 // new base register, clobbering the previous base register. Never share a
1463 // base reg across different basic blocks. This isn't ideal if local and 1602 // base reg across different basic blocks. This isn't ideal if local and
1464 // multi-block variables are far apart and their references are interspersed. 1603 // multi-block variables are far apart and their references are interspersed.
1465 // It may help to be more coordinated about assign stack slot numbers and may 1604 // It may help to be more coordinated about assign stack slot numbers and may
1466 // help to assign smaller offsets to higher-weight variables so that they 1605 // help to assign smaller offsets to higher-weight variables so that they
1467 // don't depend on this legalization. 1606 // don't depend on this legalization.
1468 for (CfgNode *Node : Func->getNodes()) { 1607 for (CfgNode *Node : Func->getNodes()) {
1469 Context.init(Node); 1608 Context.init(Node);
1470 Variable *NewBaseReg = nullptr; 1609 // One legalizer per basic block, otherwise we would share the Temporary
1471 int32_t NewBaseOffset = 0; 1610 // Base Register between basic blocks.
1611 PostLoweringLegalizer Legalizer(this);
1472 while (!Context.atEnd()) { 1612 while (!Context.atEnd()) {
1473 PostIncrLoweringContext PostIncrement(Context); 1613 PostIncrLoweringContext PostIncrement(Context);
1474 Inst *CurInstr = Context.getCur(); 1614 Inst *CurInstr = Context.getCur();
1475 Variable *Dest = CurInstr->getDest();
1476 1615
1477 // Check if the previous NewBaseReg is clobbered, and reset if needed. 1616 // Check if the previous TempBaseReg is clobbered, and reset if needed.
1478 if ((Dest && NewBaseReg && Dest->hasReg() && 1617 Legalizer.resetTempBaseIfClobberedBy(CurInstr);
1479 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) || 1618
1480 llvm::isa<InstFakeKill>(CurInstr)) { 1619 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) {
1481 NewBaseReg = nullptr; 1620 Legalizer.legalizeMov(MovInstr);
1482 NewBaseOffset = 0; 1621 } else if (auto *LdrInstr = llvm::dyn_cast<InstARM32Ldr>(CurInstr)) {
1622 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
1623 llvm::cast<OperandARM32Mem>(LdrInstr->getSrc(0)))) {
1624 _ldr(CurInstr->getDest(), LegalMem, LdrInstr->getPredicate());
1625 CurInstr->setDeleted();
1626 }
1627 } else if (auto *LdrexInstr = llvm::dyn_cast<InstARM32Ldrex>(CurInstr)) {
1628 constexpr bool DisallowOffsetsBecauseLdrex = false;
1629 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
1630 llvm::cast<OperandARM32Mem>(LdrexInstr->getSrc(0)),
1631 DisallowOffsetsBecauseLdrex)) {
1632 _ldrex(CurInstr->getDest(), LegalMem, LdrexInstr->getPredicate());
1633 CurInstr->setDeleted();
1634 }
1635 } else if (auto *StrInstr = llvm::dyn_cast<InstARM32Str>(CurInstr)) {
1636 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
1637 llvm::cast<OperandARM32Mem>(StrInstr->getSrc(1)))) {
1638 _str(llvm::cast<Variable>(CurInstr->getSrc(0)), LegalMem,
1639 StrInstr->getPredicate());
1640 CurInstr->setDeleted();
1641 }
1642 } else if (auto *StrexInstr = llvm::dyn_cast<InstARM32Strex>(CurInstr)) {
1643 constexpr bool DisallowOffsetsBecauseStrex = false;
1644 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
1645 llvm::cast<OperandARM32Mem>(StrexInstr->getSrc(1)),
1646 DisallowOffsetsBecauseStrex)) {
1647 _strex(CurInstr->getDest(), llvm::cast<Variable>(CurInstr->getSrc(0)),
1648 LegalMem, StrexInstr->getPredicate());
1649 CurInstr->setDeleted();
1650 }
1483 } 1651 }
1484 1652
1485 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { 1653 // Sanity-check: the Legalizer will either have no Temp, or it will be
1486 legalizeMov(MovInstr, OrigBaseReg, &NewBaseReg, &NewBaseOffset); 1654 // bound to IP.
1487 } 1655 Legalizer.assertNoTempOrAssignedToIP();
1488 } 1656 }
1489 } 1657 }
1490 } 1658 }
1491 1659
1492 Operand *TargetARM32::loOperand(Operand *Operand) { 1660 Operand *TargetARM32::loOperand(Operand *Operand) {
1493 assert(Operand->getType() == IceType_i64); 1661 assert(Operand->getType() == IceType_i64);
1494 if (Operand->getType() != IceType_i64) 1662 if (Operand->getType() != IceType_i64)
1495 return Operand; 1663 return Operand;
1496 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) 1664 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
1497 return Var64On32->getLo(); 1665 return Var64On32->getLo();
1498 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) 1666 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand))
1499 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue())); 1667 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue()));
1500 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) { 1668 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
1501 // Conservatively disallow memory operands with side-effects (pre/post 1669 // Conservatively disallow memory operands with side-effects (pre/post
1502 // increment) in case of duplication. 1670 // increment) in case of duplication.
1503 assert(Mem->getAddrMode() == OperandARM32Mem::Offset || 1671 assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
1504 Mem->getAddrMode() == OperandARM32Mem::NegOffset); 1672 Mem->getAddrMode() == OperandARM32Mem::NegOffset);
1505 Variable *BaseR = legalizeToReg(Mem->getBase());
1506 if (Mem->isRegReg()) { 1673 if (Mem->isRegReg()) {
1507 Variable *IndexR = legalizeToReg(Mem->getIndex()); 1674 Variable *IndexR = legalizeToReg(Mem->getIndex());
1508 return OperandARM32Mem::create(Func, IceType_i32, BaseR, IndexR, 1675 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(), IndexR,
1509 Mem->getShiftOp(), Mem->getShiftAmt(), 1676 Mem->getShiftOp(), Mem->getShiftAmt(),
1510 Mem->getAddrMode()); 1677 Mem->getAddrMode());
1511 } else { 1678 } else {
1512 return OperandARM32Mem::create(Func, IceType_i32, BaseR, Mem->getOffset(), 1679 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(),
1513 Mem->getAddrMode()); 1680 Mem->getOffset(), Mem->getAddrMode());
1514 } 1681 }
1515 } 1682 }
1516 llvm::report_fatal_error("Unsupported operand type"); 1683 llvm::report_fatal_error("Unsupported operand type");
1517 return nullptr; 1684 return nullptr;
1518 } 1685 }
1519 1686
1520 Operand *TargetARM32::hiOperand(Operand *Operand) { 1687 Operand *TargetARM32::hiOperand(Operand *Operand) {
1521 assert(Operand->getType() == IceType_i64); 1688 assert(Operand->getType() == IceType_i64);
1522 if (Operand->getType() != IceType_i64) 1689 if (Operand->getType() != IceType_i64)
1523 return Operand; 1690 return Operand;
(...skipping 3260 matching lines...) Expand 10 before | Expand all | Expand 10 after
4784 4951
4785 // Update the computed address parameters once we are sure optimization 4952 // Update the computed address parameters once we are sure optimization
4786 // is valid. 4953 // is valid.
4787 *Base = NewBase; 4954 *Base = NewBase;
4788 *Offset = NewOffset; 4955 *Offset = NewOffset;
4789 *Reason = BaseInst; 4956 *Reason = BaseInst;
4790 return true; 4957 return true;
4791 } 4958 }
4792 } // end of anonymous namespace 4959 } // end of anonymous namespace
4793 4960
4794 // ARM32 address modes:
4795 // ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12],
4796 // [reg +/- reg << shamt5]
4797 // ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8]
4798 // ld/st vectors : [reg]
4799 //
4800 // For now, we don't handle address modes with Relocatables.
4801 namespace {
4802 // MemTraits contains per-type valid address mode information.
4803 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \
4804 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag);
4805 ICETYPEARM32_TABLE
4806 #undef X
4807
4808 static const struct {
4809 int32_t ValidImmMask;
4810 bool CanHaveImm;
4811 bool CanHaveIndex;
4812 bool CanHaveShiftedIndex;
4813 } MemTraits[] = {
4814 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \
4815 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \
4816 ,
4817 ICETYPEARM32_TABLE
4818 #undef X
4819 };
4820 static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits);
4821 } // end of anonymous namespace
4822
4823 OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func, 4961 OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func,
4824 const Inst *LdSt, 4962 const Inst *LdSt,
4825 Operand *Base) { 4963 Operand *Base) {
4826 assert(Base != nullptr); 4964 assert(Base != nullptr);
4827 int32_t OffsetImm = 0; 4965 int32_t OffsetImm = 0;
4828 Variable *OffsetReg = nullptr; 4966 Variable *OffsetReg = nullptr;
4829 int32_t OffsetRegShamt = 0; 4967 int32_t OffsetRegShamt = 0;
4830 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift; 4968 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift;
4831 4969
4832 Func->resetCurrentNode(); 4970 Func->resetCurrentNode();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
4948 OffsetImm = 0; 5086 OffsetImm = 0;
4949 } 5087 }
4950 } 5088 }
4951 5089
4952 assert(BaseVar != nullptr); 5090 assert(BaseVar != nullptr);
4953 assert(OffsetImm == 0 || OffsetReg == nullptr); 5091 assert(OffsetImm == 0 || OffsetReg == nullptr);
4954 assert(OffsetReg == nullptr || CanHaveIndex); 5092 assert(OffsetReg == nullptr || CanHaveIndex);
4955 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm 5093 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm
4956 : (ValidImmMask & OffsetImm) == OffsetImm); 5094 : (ValidImmMask & OffsetImm) == OffsetImm);
4957 5095
4958 Variable *BaseR = makeReg(getPointerType());
4959 Context.insert(InstAssign::create(Func, BaseR, BaseVar));
4960 if (OffsetReg != nullptr) { 5096 if (OffsetReg != nullptr) {
4961 Variable *OffsetR = makeReg(getPointerType()); 5097 Variable *OffsetR = makeReg(getPointerType());
4962 Context.insert(InstAssign::create(Func, OffsetR, OffsetReg)); 5098 Context.insert(InstAssign::create(Func, OffsetR, OffsetReg));
4963 return OperandARM32Mem::create(Func, Ty, BaseR, OffsetR, ShiftKind, 5099 return OperandARM32Mem::create(Func, Ty, BaseVar, OffsetR, ShiftKind,
4964 OffsetRegShamt); 5100 OffsetRegShamt);
4965 } 5101 }
4966 5102
4967 return OperandARM32Mem::create( 5103 return OperandARM32Mem::create(
4968 Func, Ty, BaseR, 5104 Func, Ty, BaseVar,
4969 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm))); 5105 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm)));
4970 } 5106 }
4971 5107
4972 void TargetARM32::doAddressOptLoad() { 5108 void TargetARM32::doAddressOptLoad() {
4973 Inst *Instr = Context.getCur(); 5109 Inst *Instr = Context.getCur();
4974 assert(llvm::isa<InstLoad>(Instr)); 5110 assert(llvm::isa<InstLoad>(Instr));
4975 Variable *Dest = Instr->getDest(); 5111 Variable *Dest = Instr->getDest();
4976 Operand *Addr = Instr->getSrc(0); 5112 Operand *Addr = Instr->getSrc(0);
4977 if (OperandARM32Mem *Mem = 5113 if (OperandARM32Mem *Mem =
4978 formAddressingMode(Dest->getType(), Func, Instr, Addr)) { 5114 formAddressingMode(Dest->getType(), Func, Instr, Addr)) {
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
5182 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { 5318 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) {
5183 // Before doing anything with a Mem operand, we need to ensure that the 5319 // Before doing anything with a Mem operand, we need to ensure that the
5184 // Base and Index components are in physical registers. 5320 // Base and Index components are in physical registers.
5185 Variable *Base = Mem->getBase(); 5321 Variable *Base = Mem->getBase();
5186 Variable *Index = Mem->getIndex(); 5322 Variable *Index = Mem->getIndex();
5187 ConstantInteger32 *Offset = Mem->getOffset(); 5323 ConstantInteger32 *Offset = Mem->getOffset();
5188 assert(Index == nullptr || Offset == nullptr); 5324 assert(Index == nullptr || Offset == nullptr);
5189 Variable *RegBase = nullptr; 5325 Variable *RegBase = nullptr;
5190 Variable *RegIndex = nullptr; 5326 Variable *RegIndex = nullptr;
5191 assert(Base); 5327 assert(Base);
5192 RegBase = legalizeToReg(Base); 5328 RegBase = llvm::cast<Variable>(
5329 legalize(Base, Legal_Reg | Legal_Rematerializable));
5193 assert(Ty < MemTraitsSize); 5330 assert(Ty < MemTraitsSize);
5194 if (Index) { 5331 if (Index) {
5195 assert(Offset == nullptr); 5332 assert(Offset == nullptr);
5196 assert(MemTraits[Ty].CanHaveIndex); 5333 assert(MemTraits[Ty].CanHaveIndex);
5197 RegIndex = legalizeToReg(Index); 5334 RegIndex = legalizeToReg(Index);
5198 } 5335 }
5199 if (Offset && Offset->getValue() != 0) { 5336 if (Offset && Offset->getValue() != 0) {
5200 assert(Index == nullptr); 5337 assert(Index == nullptr);
5201 static constexpr bool ZeroExt = false; 5338 static constexpr bool ZeroExt = false;
5202 assert(MemTraits[Ty].CanHaveImm); 5339 assert(MemTraits[Ty].CanHaveImm);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
5317 Variable *BaseReg = makeReg(getPointerType()); 5454 Variable *BaseReg = makeReg(getPointerType());
5318 _movw(BaseReg, Offset); 5455 _movw(BaseReg, Offset);
5319 _movt(BaseReg, Offset); 5456 _movt(BaseReg, Offset);
5320 From = formMemoryOperand(BaseReg, Ty); 5457 From = formMemoryOperand(BaseReg, Ty);
5321 return copyToReg(From, RegNum); 5458 return copyToReg(From, RegNum);
5322 } 5459 }
5323 } 5460 }
5324 5461
5325 if (auto *Var = llvm::dyn_cast<Variable>(From)) { 5462 if (auto *Var = llvm::dyn_cast<Variable>(From)) {
5326 if (Var->isRematerializable()) { 5463 if (Var->isRematerializable()) {
5464 if (Allowed & Legal_Rematerializable) {
5465 return From;
5466 }
5467
5327 // TODO(jpp): We don't need to rematerialize Var if legalize() was invoked 5468 // TODO(jpp): We don't need to rematerialize Var if legalize() was invoked
5328 // for a Variable in a Mem operand. 5469 // for a Variable in a Mem operand.
5329 Variable *T = makeReg(Var->getType(), RegNum); 5470 Variable *T = makeReg(Var->getType(), RegNum);
5330 _mov(T, Var); 5471 _mov(T, Var);
5331 return T; 5472 return T;
5332 } 5473 }
5333 // Check if the variable is guaranteed a physical register. This can happen 5474 // Check if the variable is guaranteed a physical register. This can happen
5334 // either when the variable is pre-colored or when it is assigned infinite 5475 // either when the variable is pre-colored or when it is assigned infinite
5335 // weight. 5476 // weight.
5336 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg()); 5477 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
5379 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); 5520 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand);
5380 // It may be the case that address mode optimization already creates an 5521 // It may be the case that address mode optimization already creates an
5381 // OperandARM32Mem, so in that case it wouldn't need another level of 5522 // OperandARM32Mem, so in that case it wouldn't need another level of
5382 // transformation. 5523 // transformation.
5383 if (Mem) { 5524 if (Mem) {
5384 return llvm::cast<OperandARM32Mem>(legalize(Mem)); 5525 return llvm::cast<OperandARM32Mem>(legalize(Mem));
5385 } 5526 }
5386 // If we didn't do address mode optimization, then we only have a 5527 // If we didn't do address mode optimization, then we only have a
5387 // base/offset to work with. ARM always requires a base register, so 5528 // base/offset to work with. ARM always requires a base register, so
5388 // just use that to hold the operand. 5529 // just use that to hold the operand.
5389 Variable *BaseR = legalizeToReg(Operand); 5530 Variable *Base = llvm::cast<Variable>(
5531 legalize(Operand, Legal_Reg | Legal_Rematerializable));
5390 return OperandARM32Mem::create( 5532 return OperandARM32Mem::create(
5391 Func, Ty, BaseR, 5533 Func, Ty, Base,
5392 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); 5534 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32)));
5393 } 5535 }
5394 5536
5395 Variable64On32 *TargetARM32::makeI64RegPair() { 5537 Variable64On32 *TargetARM32::makeI64RegPair() {
5396 Variable64On32 *Reg = 5538 Variable64On32 *Reg =
5397 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); 5539 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
5398 Reg->setMustHaveReg(); 5540 Reg->setMustHaveReg();
5399 Reg->initHiLo(Func); 5541 Reg->initHiLo(Func);
5400 Reg->getLo()->setMustNotHaveReg(); 5542 Reg->getLo()->setMustNotHaveReg();
5401 Reg->getHi()->setMustNotHaveReg(); 5543 Reg->getHi()->setMustNotHaveReg();
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after
5958 // Technically R9 is used for TLS with Sandboxing, and we reserve it. 6100 // Technically R9 is used for TLS with Sandboxing, and we reserve it.
5959 // However, for compatibility with current NaCl LLVM, don't claim that. 6101 // However, for compatibility with current NaCl LLVM, don't claim that.
5960 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; 6102 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n";
5961 } 6103 }
5962 6104
5963 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; 6105 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM];
5964 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; 6106 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM];
5965 llvm::SmallBitVector TargetARM32::ScratchRegs; 6107 llvm::SmallBitVector TargetARM32::ScratchRegs;
5966 6108
5967 } // end of namespace Ice 6109 } // end of namespace Ice
OLDNEW
« no previous file with comments | « src/IceTargetLoweringARM32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698