diff options
| author | Peter Collingbourne <peter@pcc.me.uk> | 2018-04-23 19:09:34 +0000 |
|---|---|---|
| committer | Peter Collingbourne <peter@pcc.me.uk> | 2018-04-23 19:09:34 +0000 |
| commit | 5ab4a4793efbe8805c3fedc8f6625ebad987ce7b (patch) | |
| tree | f160a8e343181015aee8ce2b4d54dc4e1dee4794 /llvm/lib/Target | |
| parent | cc45e923c5c1be906ad9b56b2665b954f78c4a49 (diff) | |
| download | bcm5719-llvm-5ab4a4793efbe8805c3fedc8f6625ebad987ce7b.tar.gz bcm5719-llvm-5ab4a4793efbe8805c3fedc8f6625ebad987ce7b.zip | |
Reland r329956, "AArch64: Introduce a DAG combine for folding offsets into addresses.", with a fix for the bot failure.
This reland includes a check to prevent the DAG combiner from folding an
offset that is smaller than the existing one. This can cause oscillations
between two possible DAGs, which was the cause of the hang and later assertion
failure observed on the lnt-ctmark-aarch64-O3-flto bot.
http://green.lab.llvm.org/green/job/lnt-ctmark-aarch64-O3-flto/2024/
Original commit message:
> This is a code size win in code that takes offseted addresses
> frequently, such as C++ constructors that typically need to compute
> an offseted address of a vtable. This reduces the size of Chromium
> for Android's .text section by 108KB.
Differential Revision: https://reviews.llvm.org/D45199
llvm-svn: 330630
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 18 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 71 |
2 files changed, 74 insertions, 15 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index eee59f1e719..d44eee051aa 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -743,14 +743,16 @@ bool AArch64DAGToDAGISel::SelectAddrModeIndexed(SDValue N, unsigned Size, if (!GAN) return true; - const GlobalValue *GV = GAN->getGlobal(); - unsigned Alignment = GV->getAlignment(); - Type *Ty = GV->getValueType(); - if (Alignment == 0 && Ty->isSized()) - Alignment = DL.getABITypeAlignment(Ty); - - if (Alignment >= Size) - return true; + if (GAN->getOffset() % Size == 0) { + const GlobalValue *GV = GAN->getGlobal(); + unsigned Alignment = GV->getAlignment(); + Type *Ty = GV->getValueType(); + if (Alignment == 0 && Ty->isSized()) + Alignment = DL.getABITypeAlignment(Ty); + + if (Alignment >= Size) + return true; + } } if (CurDAG->isBaseWithConstantOffset(N)) { diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 19573e180ee..e12aeb46765 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -577,6 +577,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM, setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN); setTargetDAGCombine(ISD::INSERT_VECTOR_ELT); + setTargetDAGCombine(ISD::GlobalAddress); + MaxStoresPerMemset = MaxStoresPerMemsetOptSize = 8; MaxStoresPerMemcpy = MaxStoresPerMemcpyOptSize = 4; MaxStoresPerMemmove = MaxStoresPerMemmoveOptSize = 4; @@ -3677,7 +3679,8 @@ AArch64TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, SDValue AArch64TargetLowering::getTargetNode(GlobalAddressSDNode *N, EVT Ty, SelectionDAG &DAG, unsigned Flag) const { - return DAG.getTargetGlobalAddress(N->getGlobal(), SDLoc(N), Ty, 0, Flag); + return DAG.getTargetGlobalAddress(N->getGlobal(), SDLoc(N), Ty, + N->getOffset(), Flag); } SDValue AArch64TargetLowering::getTargetNode(JumpTableSDNode *N, EVT Ty, @@ -3752,8 +3755,9 @@ SDValue AArch64TargetLowering::LowerGlobalAddress(SDValue Op, unsigned char OpFlags = Subtarget->ClassifyGlobalReference(GV, getTargetMachine()); - assert(cast<GlobalAddressSDNode>(Op)->getOffset() == 0 && - "unexpected offset in global node"); + if (OpFlags != AArch64II::MO_NO_FLAG) + assert(cast<GlobalAddressSDNode>(Op)->getOffset() == 0 && + "unexpected offset in global node"); // This also catches the large code model case for Darwin. if ((OpFlags & AArch64II::MO_GOT) != 0) { @@ -4991,10 +4995,8 @@ SDValue AArch64TargetLowering::LowerShiftLeftParts(SDValue Op, bool AArch64TargetLowering::isOffsetFoldingLegal( const GlobalAddressSDNode *GA) const { - DEBUG(dbgs() << "Skipping offset folding global address: "); - DEBUG(GA->dump()); - DEBUG(dbgs() << "AArch64 doesn't support folding offsets into global " - "addresses\n"); + // Offsets are folded in the DAG combine rather than here so that we can + // intelligently choose an offset based on the uses. return false; } @@ -10617,6 +10619,59 @@ static SDValue performNVCASTCombine(SDNode *N) { return SDValue(); } +// If all users of the globaladdr are of the form (globaladdr + constant), find +// the smallest constant, fold it into the globaladdr's offset and rewrite the +// globaladdr as (globaladdr + constant) - constant. +static SDValue performGlobalAddressCombine(SDNode *N, SelectionDAG &DAG, + const AArch64Subtarget *Subtarget, + const TargetMachine &TM) { + auto *GN = dyn_cast<GlobalAddressSDNode>(N); + if (!GN || Subtarget->ClassifyGlobalReference(GN->getGlobal(), TM) != + AArch64II::MO_NO_FLAG) + return SDValue(); + + uint64_t MinOffset = -1ull; + for (SDNode *N : GN->uses()) { + if (N->getOpcode() != ISD::ADD) + return SDValue(); + auto *C = dyn_cast<ConstantSDNode>(N->getOperand(0)); + if (!C) + C = dyn_cast<ConstantSDNode>(N->getOperand(1)); + if (!C) + return SDValue(); + MinOffset = std::min(MinOffset, C->getZExtValue()); + } + uint64_t Offset = MinOffset + GN->getOffset(); + + // Require that the new offset is larger than the existing one. Otherwise, we + // can end up oscillating between two possible DAGs, for example, + // (add (add globaladdr + 10, -1), 1) and (add globaladdr + 9, 1). + if (Offset <= uint64_t(GN->getOffset())) + return SDValue(); + + // Check whether folding this offset is legal. It must not go out of bounds of + // the referenced object to avoid violating the code model, and must be + // smaller than 2^21 because this is the largest offset expressible in all + // object formats. + // + // This check also prevents us from folding negative offsets, which will end + // up being treated in the same way as large positive ones. They could also + // cause code model violations, and aren't really common enough to matter. + if (Offset >= (1 << 21)) + return SDValue(); + + const GlobalValue *GV = GN->getGlobal(); + Type *T = GV->getValueType(); + if (!T->isSized() || + Offset > GV->getParent()->getDataLayout().getTypeAllocSize(T)) + return SDValue(); + + SDLoc DL(GN); + SDValue Result = DAG.getGlobalAddress(GV, DL, MVT::i64, Offset); + return DAG.getNode(ISD::SUB, DL, MVT::i64, Result, + DAG.getConstant(MinOffset, DL, MVT::i64)); +} + SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; @@ -10704,6 +10759,8 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N, default: break; } + case ISD::GlobalAddress: + return performGlobalAddressCombine(N, DAG, Subtarget, getTargetMachine()); } return SDValue(); } |

