From bcc57c0a399648342de5c33f7e97d8f47229a9ac Mon Sep 17 00:00:00 2001 From: Hal Finkel Date: Fri, 2 Sep 2016 21:37:07 +0000 Subject: [PATCH] [PowerPC] For larger offsets, when possible, fold offset into addis toc@ha When we have an offset into a global, etc. that is accessed relative to the TOC base pointer, and the offset is larger than the minimum alignment of the global itself and the TOC base pointer (which is 8-byte aligned), we can still fold the @toc@ha into the memory access, but we must update the addis instruction's symbol reference with the offset as the symbol addend. When there is only one use of the addi to be folded and only one use of the addis that would need its symbol's offset adjusted, then we can make the adjustment and fold the @toc@l into the memory access. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280545 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/PowerPC/PPCAsmPrinter.cpp | 7 +++++++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 29 +++++++++++++++++++++++++++-- test/CodeGen/PowerPC/peephole-align.ll | 6 ++---- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/lib/Target/PowerPC/PPCAsmPrinter.cpp b/lib/Target/PowerPC/PPCAsmPrinter.cpp index 5bdec80ac42..5813abe527d 100644 --- a/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -673,6 +673,13 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_HA, OutContext); + + if (!MO.isJTI() && MO.getOffset()) + Exp = MCBinaryExpr::createAdd(Exp, + MCConstantExpr::create(MO.getOffset(), + OutContext), + OutContext); + TmpInst.getOperand(2) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; diff --git a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 23ee3e7312f..56e39221edf 100644 --- a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -4381,9 +4381,30 @@ void PPCDAGToDAGISel::PeepholePPC64() { MaxDisplacement = std::min((int) GV->getAlignment() - 1, MaxDisplacement); } + bool UpdateHBase = false; + SDValue HBase = Base.getOperand(0); + int Offset = N->getConstantOperandVal(FirstOp); - if (Offset < 0 || Offset > MaxDisplacement) - continue; + if (Offset < 0 || Offset > MaxDisplacement) { + // If we have a addi(toc@l)/addis(toc@ha) pair, and the addis has only + // one use, then we can do this for any offset, we just need to also + // update the offset (i.e. the symbol addend) on the addis also. + if (Base.getMachineOpcode() != PPC::ADDItocL) + continue; + + if (!HBase.isMachineOpcode() || + HBase.getMachineOpcode() != PPC::ADDIStocHA) + continue; + + if (!Base.hasOneUse() || !HBase.hasOneUse()) + continue; + + SDValue HImmOpnd = HBase.getOperand(1); + if (HImmOpnd != ImmOpnd) + continue; + + UpdateHBase = true; + } // We found an opportunity. Reverse the operands from the add // immediate and substitute them into the load or store. If @@ -4426,6 +4447,10 @@ void PPCDAGToDAGISel::PeepholePPC64() { (void)CurDAG->UpdateNodeOperands(N, ImmOpnd, Base.getOperand(0), N->getOperand(2)); + if (UpdateHBase) + (void)CurDAG->UpdateNodeOperands(HBase.getNode(), HBase.getOperand(0), + ImmOpnd); + // The add-immediate may now be dead, in which case remove it. if (Base.getNode()->use_empty()) CurDAG->RemoveDeadNode(Base.getNode()); diff --git a/test/CodeGen/PowerPC/peephole-align.ll b/test/CodeGen/PowerPC/peephole-align.ll index 1be84170734..3b35e6234bd 100644 --- a/test/CodeGen/PowerPC/peephole-align.ll +++ b/test/CodeGen/PowerPC/peephole-align.ll @@ -227,11 +227,9 @@ entry: ret void } -; register 3 is the return value, so it should be chosen ; CHECK-LABEL: test_singleuse: -; CHECK: addis 3, 2, d2v@toc@ha -; CHECK: addi 3, 3, d2v@toc@l -; CHECK: ld 3, 8(3) +; CHECK: addis [[REG:[0-9]+]], 2, d2v@toc@ha+8 +; CHECK: ld 3, d2v@toc@l+8([[REG]]) define i64 @test_singleuse() nounwind { entry: %0 = load i64, i64* getelementptr inbounds (%struct.d2, %struct.d2* @d2v, i32 0, i32 1), align 8 -- 2.11.0