From e5ba580ab05b18eaa9fd4d36e31466e41f693ad9 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 22 Mar 2006 05:26:03 +0000 Subject: [PATCH] Add support for "ri" addressing modes where the immediate is a 14-bit field which is shifted left two bits before use. Instructions like STD use this addressing mode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26942 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/PowerPC/PPCAsmPrinter.cpp | 14 ++++++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 81 ++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/lib/Target/PowerPC/PPCAsmPrinter.cpp b/lib/Target/PowerPC/PPCAsmPrinter.cpp index 9b33dd4bcba..6fb6e5fd1e3 100644 --- a/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -201,6 +201,20 @@ namespace { printOperand(MI, OpNo+1); O << ')'; } + void printMemRegImmShifted(const MachineInstr *MI, unsigned OpNo) { + if (MI->getOperand(OpNo).isImmediate()) + printS16X4ImmOperand(MI, OpNo); + else + printSymbolLo(MI, OpNo); + O << '('; + if (MI->getOperand(OpNo+1).isRegister() && + MI->getOperand(OpNo+1).getReg() == PPC::R0) + O << "0"; + else + printOperand(MI, OpNo+1); + O << ')'; + } + void printMemRegReg(const MachineInstr *MI, unsigned OpNo) { // When used as the base register, r0 reads constant zero rather than // the value contained in the register. For this reason, the darwin diff --git a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index f5fc33aee60..459ddfaeb8e 100644 --- a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -89,6 +89,11 @@ namespace { /// represented as an indexed [r+r] operation. bool SelectAddrIdxOnly(SDOperand N, SDOperand &Base, SDOperand &Index); + /// SelectAddrImmShift - Returns true if the address N can be represented by + /// a base register plus a signed 14-bit displacement [r+imm*4]. Suitable + /// for use by STD and friends. + bool SelectAddrImmShift(SDOperand N, SDOperand &Disp, SDOperand &Base); + /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. virtual bool SelectInlineAsmMemoryOperand(const SDOperand &Op, @@ -619,6 +624,82 @@ bool PPCDAGToDAGISel::SelectAddrIdxOnly(SDOperand N, SDOperand &Base, return true; } +/// SelectAddrImmShift - Returns true if the address N can be represented by +/// a base register plus a signed 14-bit displacement [r+imm*4]. Suitable +/// for use by STD and friends. +bool PPCDAGToDAGISel::SelectAddrImmShift(SDOperand N, SDOperand &Disp, + SDOperand &Base) { + // If this can be more profitably realized as r+r, fail. + if (SelectAddrIdx(N, Disp, Base)) + return false; + + if (N.getOpcode() == ISD::ADD) { + unsigned imm = 0; + if (isIntImmediate(N.getOperand(1), imm) && isInt16(imm) && + (imm & 3) == 0) { + Disp = getI32Imm((imm & 0xFFFF) >> 2); + if (FrameIndexSDNode *FI = dyn_cast(N.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FI->getIndex(), MVT::i32); + } else { + Base = N.getOperand(0); + } + return true; // [r+i] + } else if (N.getOperand(1).getOpcode() == PPCISD::Lo) { + // Match LOAD (ADD (X, Lo(G))). + assert(!cast(N.getOperand(1).getOperand(1))->getValue() + && "Cannot handle constant offsets yet!"); + Disp = N.getOperand(1).getOperand(0); // The global address. + assert(Disp.getOpcode() == ISD::TargetGlobalAddress || + Disp.getOpcode() == ISD::TargetConstantPool); + Base = N.getOperand(0); + return true; // [&g+r] + } + } else if (N.getOpcode() == ISD::OR) { + unsigned imm = 0; + if (isIntImmediate(N.getOperand(1), imm) && isInt16(imm) && + (imm & 3) == 0) { + // If this is an or of disjoint bitfields, we can codegen this as an add + // (for better address arithmetic) if the LHS and RHS of the OR are + // provably disjoint. + uint64_t LHSKnownZero, LHSKnownOne; + PPCLowering.ComputeMaskedBits(N.getOperand(0), ~0U, + LHSKnownZero, LHSKnownOne); + if ((LHSKnownZero|~imm) == ~0U) { + // If all of the bits are known zero on the LHS or RHS, the add won't + // carry. + Base = N.getOperand(0); + Disp = getI32Imm((imm & 0xFFFF) >> 2); + return true; + } + } + } else if (ConstantSDNode *CN = dyn_cast(N)) { + // Loading from a constant address. + int Addr = (int)CN->getValue(); + if ((Addr & 3) == 0) { + // If this address fits entirely in a 16-bit sext immediate field, codegen + // this as "d, 0" + if (Addr == (short)Addr) { + Disp = getI32Imm(Addr >> 2); + Base = CurDAG->getRegister(PPC::R0, MVT::i32); + return true; + } + + // Otherwise, break this down into an LIS + disp. + Disp = getI32Imm((short)Addr >> 2); + Base = CurDAG->getConstant(Addr - (signed short)Addr, MVT::i32); + return true; + } + } + + Disp = getI32Imm(0); + if (FrameIndexSDNode *FI = dyn_cast(N)) + Base = CurDAG->getTargetFrameIndex(FI->getIndex(), MVT::i32); + else + Base = N; + return true; // [r+0] +} + + /// SelectCC - Select a comparison of the specified values with the specified /// condition code, returning the CR# of the expression. SDOperand PPCDAGToDAGISel::SelectCC(SDOperand LHS, SDOperand RHS, -- 2.11.0