mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-26 07:29:55 +00:00
DoInstructionSelection. Inline "SelectRoot" into it from DAGISelHeader. Sink some other stuff out of DAGISelHeader into SDISel. Eliminate the various 'Indent' stuff from various targets, which dates to when isel was recursive. 17 files changed, 114 insertions(+), 430 deletions(-) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@97555 91177308-0d34-0410-b5e6-96231b3b80d8
784 lines
27 KiB
C++
784 lines
27 KiB
C++
//==-- SystemZISelDAGToDAG.cpp - A dag to dag inst selector for SystemZ ---===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines an instruction selector for the SystemZ target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SystemZ.h"
|
|
#include "SystemZISelLowering.h"
|
|
#include "SystemZTargetMachine.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "llvm/Function.h"
|
|
#include "llvm/Intrinsics.h"
|
|
#include "llvm/CallingConv.h"
|
|
#include "llvm/Constants.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/Target/TargetLowering.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
static const unsigned subreg_even32 = 1;
|
|
static const unsigned subreg_odd32 = 2;
|
|
static const unsigned subreg_even = 3;
|
|
static const unsigned subreg_odd = 4;
|
|
|
|
namespace {
|
|
/// SystemZRRIAddressMode - This corresponds to rriaddr, but uses SDValue's
|
|
/// instead of register numbers for the leaves of the matched tree.
|
|
struct SystemZRRIAddressMode {
|
|
enum {
|
|
RegBase,
|
|
FrameIndexBase
|
|
} BaseType;
|
|
|
|
struct { // This is really a union, discriminated by BaseType!
|
|
SDValue Reg;
|
|
int FrameIndex;
|
|
} Base;
|
|
|
|
SDValue IndexReg;
|
|
int64_t Disp;
|
|
bool isRI;
|
|
|
|
SystemZRRIAddressMode(bool RI = false)
|
|
: BaseType(RegBase), IndexReg(), Disp(0), isRI(RI) {
|
|
}
|
|
|
|
void dump() {
|
|
errs() << "SystemZRRIAddressMode " << this << '\n';
|
|
if (BaseType == RegBase) {
|
|
errs() << "Base.Reg ";
|
|
if (Base.Reg.getNode() != 0)
|
|
Base.Reg.getNode()->dump();
|
|
else
|
|
errs() << "nul";
|
|
errs() << '\n';
|
|
} else {
|
|
errs() << " Base.FrameIndex " << Base.FrameIndex << '\n';
|
|
}
|
|
if (!isRI) {
|
|
errs() << "IndexReg ";
|
|
if (IndexReg.getNode() != 0) IndexReg.getNode()->dump();
|
|
else errs() << "nul";
|
|
}
|
|
errs() << " Disp " << Disp << '\n';
|
|
}
|
|
};
|
|
}
|
|
|
|
/// SystemZDAGToDAGISel - SystemZ specific code to select SystemZ machine
|
|
/// instructions for SelectionDAG operations.
|
|
///
|
|
namespace {
|
|
class SystemZDAGToDAGISel : public SelectionDAGISel {
|
|
SystemZTargetLowering &Lowering;
|
|
const SystemZSubtarget &Subtarget;
|
|
|
|
void getAddressOperandsRI(const SystemZRRIAddressMode &AM,
|
|
SDValue &Base, SDValue &Disp);
|
|
void getAddressOperands(const SystemZRRIAddressMode &AM,
|
|
SDValue &Base, SDValue &Disp,
|
|
SDValue &Index);
|
|
|
|
public:
|
|
SystemZDAGToDAGISel(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel)
|
|
: SelectionDAGISel(TM, OptLevel),
|
|
Lowering(*TM.getTargetLowering()),
|
|
Subtarget(*TM.getSubtargetImpl()) { }
|
|
|
|
virtual const char *getPassName() const {
|
|
return "SystemZ DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
/// getI8Imm - Return a target constant with the specified value, of type
|
|
/// i8.
|
|
inline SDValue getI8Imm(uint64_t Imm) {
|
|
return CurDAG->getTargetConstant(Imm, MVT::i8);
|
|
}
|
|
|
|
/// getI16Imm - Return a target constant with the specified value, of type
|
|
/// i16.
|
|
inline SDValue getI16Imm(uint64_t Imm) {
|
|
return CurDAG->getTargetConstant(Imm, MVT::i16);
|
|
}
|
|
|
|
/// getI32Imm - Return a target constant with the specified value, of type
|
|
/// i32.
|
|
inline SDValue getI32Imm(uint64_t Imm) {
|
|
return CurDAG->getTargetConstant(Imm, MVT::i32);
|
|
}
|
|
|
|
// Include the pieces autogenerated from the target description.
|
|
#include "SystemZGenDAGISel.inc"
|
|
|
|
private:
|
|
bool SelectAddrRI12Only(SDNode *Op, SDValue& Addr,
|
|
SDValue &Base, SDValue &Disp);
|
|
bool SelectAddrRI12(SDNode *Op, SDValue& Addr,
|
|
SDValue &Base, SDValue &Disp,
|
|
bool is12BitOnly = false);
|
|
bool SelectAddrRI(SDNode *Op, SDValue& Addr,
|
|
SDValue &Base, SDValue &Disp);
|
|
bool SelectAddrRRI12(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index);
|
|
bool SelectAddrRRI20(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index);
|
|
bool SelectLAAddr(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index);
|
|
|
|
SDNode *Select(SDNode *Node);
|
|
|
|
bool TryFoldLoad(SDNode *P, SDValue N,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index);
|
|
|
|
bool MatchAddress(SDValue N, SystemZRRIAddressMode &AM,
|
|
bool is12Bit, unsigned Depth = 0);
|
|
bool MatchAddressBase(SDValue N, SystemZRRIAddressMode &AM);
|
|
bool MatchAddressRI(SDValue N, SystemZRRIAddressMode &AM,
|
|
bool is12Bit);
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
/// createSystemZISelDag - This pass converts a legalized DAG into a
|
|
/// SystemZ-specific DAG, ready for instruction scheduling.
|
|
///
|
|
FunctionPass *llvm::createSystemZISelDag(SystemZTargetMachine &TM,
|
|
CodeGenOpt::Level OptLevel) {
|
|
return new SystemZDAGToDAGISel(TM, OptLevel);
|
|
}
|
|
|
|
/// isImmSExt20 - This method tests to see if the node is either a 32-bit
|
|
/// or 64-bit immediate, and if the value can be accurately represented as a
|
|
/// sign extension from a 20-bit value. If so, this returns true and the
|
|
/// immediate.
|
|
static bool isImmSExt20(int64_t Val, int64_t &Imm) {
|
|
if (Val >= -524288 && Val <= 524287) {
|
|
Imm = Val;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// isImmZExt12 - This method tests to see if the node is either a 32-bit
|
|
/// or 64-bit immediate, and if the value can be accurately represented as a
|
|
/// zero extension from a 12-bit value. If so, this returns true and the
|
|
/// immediate.
|
|
static bool isImmZExt12(int64_t Val, int64_t &Imm) {
|
|
if (Val >= 0 && Val <= 0xFFF) {
|
|
Imm = Val;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// MatchAddress - Add the specified node to the specified addressing mode,
|
|
/// returning true if it cannot be done. This just pattern matches for the
|
|
/// addressing mode.
|
|
bool SystemZDAGToDAGISel::MatchAddress(SDValue N, SystemZRRIAddressMode &AM,
|
|
bool is12Bit, unsigned Depth) {
|
|
DebugLoc dl = N.getDebugLoc();
|
|
DEBUG(errs() << "MatchAddress: "; AM.dump());
|
|
// Limit recursion.
|
|
if (Depth > 5)
|
|
return MatchAddressBase(N, AM);
|
|
|
|
// FIXME: We can perform better here. If we have something like
|
|
// (shift (add A, imm), N), we can try to reassociate stuff and fold shift of
|
|
// imm into addressing mode.
|
|
switch (N.getOpcode()) {
|
|
default: break;
|
|
case ISD::Constant: {
|
|
int64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
|
|
int64_t Imm = 0;
|
|
bool Match = (is12Bit ?
|
|
isImmZExt12(AM.Disp + Val, Imm) :
|
|
isImmSExt20(AM.Disp + Val, Imm));
|
|
if (Match) {
|
|
AM.Disp = Imm;
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ISD::FrameIndex:
|
|
if (AM.BaseType == SystemZRRIAddressMode::RegBase &&
|
|
AM.Base.Reg.getNode() == 0) {
|
|
AM.BaseType = SystemZRRIAddressMode::FrameIndexBase;
|
|
AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case ISD::SUB: {
|
|
// Given A-B, if A can be completely folded into the address and
|
|
// the index field with the index field unused, use -B as the index.
|
|
// This is a win if a has multiple parts that can be folded into
|
|
// the address. Also, this saves a mov if the base register has
|
|
// other uses, since it avoids a two-address sub instruction, however
|
|
// it costs an additional mov if the index register has other uses.
|
|
|
|
// Test if the LHS of the sub can be folded.
|
|
SystemZRRIAddressMode Backup = AM;
|
|
if (MatchAddress(N.getNode()->getOperand(0), AM, is12Bit, Depth+1)) {
|
|
AM = Backup;
|
|
break;
|
|
}
|
|
// Test if the index field is free for use.
|
|
if (AM.IndexReg.getNode() || AM.isRI) {
|
|
AM = Backup;
|
|
break;
|
|
}
|
|
|
|
// If the base is a register with multiple uses, this transformation may
|
|
// save a mov. Otherwise it's probably better not to do it.
|
|
if (AM.BaseType == SystemZRRIAddressMode::RegBase &&
|
|
(!AM.Base.Reg.getNode() || AM.Base.Reg.getNode()->hasOneUse())) {
|
|
AM = Backup;
|
|
break;
|
|
}
|
|
|
|
// Ok, the transformation is legal and appears profitable. Go for it.
|
|
SDValue RHS = N.getNode()->getOperand(1);
|
|
SDValue Zero = CurDAG->getConstant(0, N.getValueType());
|
|
SDValue Neg = CurDAG->getNode(ISD::SUB, dl, N.getValueType(), Zero, RHS);
|
|
AM.IndexReg = Neg;
|
|
|
|
// Insert the new nodes into the topological ordering.
|
|
if (Zero.getNode()->getNodeId() == -1 ||
|
|
Zero.getNode()->getNodeId() > N.getNode()->getNodeId()) {
|
|
CurDAG->RepositionNode(N.getNode(), Zero.getNode());
|
|
Zero.getNode()->setNodeId(N.getNode()->getNodeId());
|
|
}
|
|
if (Neg.getNode()->getNodeId() == -1 ||
|
|
Neg.getNode()->getNodeId() > N.getNode()->getNodeId()) {
|
|
CurDAG->RepositionNode(N.getNode(), Neg.getNode());
|
|
Neg.getNode()->setNodeId(N.getNode()->getNodeId());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
case ISD::ADD: {
|
|
SystemZRRIAddressMode Backup = AM;
|
|
if (!MatchAddress(N.getNode()->getOperand(0), AM, is12Bit, Depth+1) &&
|
|
!MatchAddress(N.getNode()->getOperand(1), AM, is12Bit, Depth+1))
|
|
return false;
|
|
AM = Backup;
|
|
if (!MatchAddress(N.getNode()->getOperand(1), AM, is12Bit, Depth+1) &&
|
|
!MatchAddress(N.getNode()->getOperand(0), AM, is12Bit, Depth+1))
|
|
return false;
|
|
AM = Backup;
|
|
|
|
// If we couldn't fold both operands into the address at the same time,
|
|
// see if we can just put each operand into a register and fold at least
|
|
// the add.
|
|
if (!AM.isRI &&
|
|
AM.BaseType == SystemZRRIAddressMode::RegBase &&
|
|
!AM.Base.Reg.getNode() && !AM.IndexReg.getNode()) {
|
|
AM.Base.Reg = N.getNode()->getOperand(0);
|
|
AM.IndexReg = N.getNode()->getOperand(1);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ISD::OR:
|
|
// Handle "X | C" as "X + C" iff X is known to have C bits clear.
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
|
|
SystemZRRIAddressMode Backup = AM;
|
|
int64_t Offset = CN->getSExtValue();
|
|
int64_t Imm = 0;
|
|
bool MatchOffset = (is12Bit ?
|
|
isImmZExt12(AM.Disp + Offset, Imm) :
|
|
isImmSExt20(AM.Disp + Offset, Imm));
|
|
// The resultant disp must fit in 12 or 20-bits.
|
|
if (MatchOffset &&
|
|
// LHS should be an addr mode.
|
|
!MatchAddress(N.getOperand(0), AM, is12Bit, Depth+1) &&
|
|
// Check to see if the LHS & C is zero.
|
|
CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) {
|
|
AM.Disp = Imm;
|
|
return false;
|
|
}
|
|
AM = Backup;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return MatchAddressBase(N, AM);
|
|
}
|
|
|
|
/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the
|
|
/// specified addressing mode without any further recursion.
|
|
bool SystemZDAGToDAGISel::MatchAddressBase(SDValue N,
|
|
SystemZRRIAddressMode &AM) {
|
|
// Is the base register already occupied?
|
|
if (AM.BaseType != SystemZRRIAddressMode::RegBase || AM.Base.Reg.getNode()) {
|
|
// If so, check to see if the index register is set.
|
|
if (AM.IndexReg.getNode() == 0 && !AM.isRI) {
|
|
AM.IndexReg = N;
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, we cannot select it.
|
|
return true;
|
|
}
|
|
|
|
// Default, generate it as a register.
|
|
AM.BaseType = SystemZRRIAddressMode::RegBase;
|
|
AM.Base.Reg = N;
|
|
return false;
|
|
}
|
|
|
|
void SystemZDAGToDAGISel::getAddressOperandsRI(const SystemZRRIAddressMode &AM,
|
|
SDValue &Base, SDValue &Disp) {
|
|
if (AM.BaseType == SystemZRRIAddressMode::RegBase)
|
|
Base = AM.Base.Reg;
|
|
else
|
|
Base = CurDAG->getTargetFrameIndex(AM.Base.FrameIndex, TLI.getPointerTy());
|
|
Disp = CurDAG->getTargetConstant(AM.Disp, MVT::i64);
|
|
}
|
|
|
|
void SystemZDAGToDAGISel::getAddressOperands(const SystemZRRIAddressMode &AM,
|
|
SDValue &Base, SDValue &Disp,
|
|
SDValue &Index) {
|
|
getAddressOperandsRI(AM, Base, Disp);
|
|
Index = AM.IndexReg;
|
|
}
|
|
|
|
/// Returns true if the address can be represented by a base register plus
|
|
/// an unsigned 12-bit displacement [r+imm].
|
|
bool SystemZDAGToDAGISel::SelectAddrRI12Only(SDNode *Op, SDValue& Addr,
|
|
SDValue &Base, SDValue &Disp) {
|
|
return SelectAddrRI12(Op, Addr, Base, Disp, /*is12BitOnly*/true);
|
|
}
|
|
|
|
bool SystemZDAGToDAGISel::SelectAddrRI12(SDNode *Op, SDValue& Addr,
|
|
SDValue &Base, SDValue &Disp,
|
|
bool is12BitOnly) {
|
|
SystemZRRIAddressMode AM20(/*isRI*/true), AM12(/*isRI*/true);
|
|
bool Done = false;
|
|
|
|
if (!Addr.hasOneUse()) {
|
|
unsigned Opcode = Addr.getOpcode();
|
|
if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) {
|
|
// If we are able to fold N into addressing mode, then we'll allow it even
|
|
// if N has multiple uses. In general, addressing computation is used as
|
|
// addresses by all of its uses. But watch out for CopyToReg uses, that
|
|
// means the address computation is liveout. It will be computed by a LA
|
|
// so we want to avoid computing the address twice.
|
|
for (SDNode::use_iterator UI = Addr.getNode()->use_begin(),
|
|
UE = Addr.getNode()->use_end(); UI != UE; ++UI) {
|
|
if (UI->getOpcode() == ISD::CopyToReg) {
|
|
MatchAddressBase(Addr, AM12);
|
|
Done = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!Done && MatchAddress(Addr, AM12, /* is12Bit */ true))
|
|
return false;
|
|
|
|
// Check, whether we can match stuff using 20-bit displacements
|
|
if (!Done && !is12BitOnly &&
|
|
!MatchAddress(Addr, AM20, /* is12Bit */ false))
|
|
if (AM12.Disp == 0 && AM20.Disp != 0)
|
|
return false;
|
|
|
|
DEBUG(errs() << "MatchAddress (final): "; AM12.dump());
|
|
|
|
EVT VT = Addr.getValueType();
|
|
if (AM12.BaseType == SystemZRRIAddressMode::RegBase) {
|
|
if (!AM12.Base.Reg.getNode())
|
|
AM12.Base.Reg = CurDAG->getRegister(0, VT);
|
|
}
|
|
|
|
assert(AM12.IndexReg.getNode() == 0 && "Invalid reg-imm address mode!");
|
|
|
|
getAddressOperandsRI(AM12, Base, Disp);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Returns true if the address can be represented by a base register plus
|
|
/// a signed 20-bit displacement [r+imm].
|
|
bool SystemZDAGToDAGISel::SelectAddrRI(SDNode *Op, SDValue& Addr,
|
|
SDValue &Base, SDValue &Disp) {
|
|
SystemZRRIAddressMode AM(/*isRI*/true);
|
|
bool Done = false;
|
|
|
|
if (!Addr.hasOneUse()) {
|
|
unsigned Opcode = Addr.getOpcode();
|
|
if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) {
|
|
// If we are able to fold N into addressing mode, then we'll allow it even
|
|
// if N has multiple uses. In general, addressing computation is used as
|
|
// addresses by all of its uses. But watch out for CopyToReg uses, that
|
|
// means the address computation is liveout. It will be computed by a LA
|
|
// so we want to avoid computing the address twice.
|
|
for (SDNode::use_iterator UI = Addr.getNode()->use_begin(),
|
|
UE = Addr.getNode()->use_end(); UI != UE; ++UI) {
|
|
if (UI->getOpcode() == ISD::CopyToReg) {
|
|
MatchAddressBase(Addr, AM);
|
|
Done = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!Done && MatchAddress(Addr, AM, /* is12Bit */ false))
|
|
return false;
|
|
|
|
DEBUG(errs() << "MatchAddress (final): "; AM.dump());
|
|
|
|
EVT VT = Addr.getValueType();
|
|
if (AM.BaseType == SystemZRRIAddressMode::RegBase) {
|
|
if (!AM.Base.Reg.getNode())
|
|
AM.Base.Reg = CurDAG->getRegister(0, VT);
|
|
}
|
|
|
|
assert(AM.IndexReg.getNode() == 0 && "Invalid reg-imm address mode!");
|
|
|
|
getAddressOperandsRI(AM, Base, Disp);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Returns true if the address can be represented by a base register plus
|
|
/// index register plus an unsigned 12-bit displacement [base + idx + imm].
|
|
bool SystemZDAGToDAGISel::SelectAddrRRI12(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index) {
|
|
SystemZRRIAddressMode AM20, AM12;
|
|
bool Done = false;
|
|
|
|
if (!Addr.hasOneUse()) {
|
|
unsigned Opcode = Addr.getOpcode();
|
|
if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) {
|
|
// If we are able to fold N into addressing mode, then we'll allow it even
|
|
// if N has multiple uses. In general, addressing computation is used as
|
|
// addresses by all of its uses. But watch out for CopyToReg uses, that
|
|
// means the address computation is liveout. It will be computed by a LA
|
|
// so we want to avoid computing the address twice.
|
|
for (SDNode::use_iterator UI = Addr.getNode()->use_begin(),
|
|
UE = Addr.getNode()->use_end(); UI != UE; ++UI) {
|
|
if (UI->getOpcode() == ISD::CopyToReg) {
|
|
MatchAddressBase(Addr, AM12);
|
|
Done = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!Done && MatchAddress(Addr, AM12, /* is12Bit */ true))
|
|
return false;
|
|
|
|
// Check, whether we can match stuff using 20-bit displacements
|
|
if (!Done && !MatchAddress(Addr, AM20, /* is12Bit */ false))
|
|
if (AM12.Disp == 0 && AM20.Disp != 0)
|
|
return false;
|
|
|
|
DEBUG(errs() << "MatchAddress (final): "; AM12.dump());
|
|
|
|
EVT VT = Addr.getValueType();
|
|
if (AM12.BaseType == SystemZRRIAddressMode::RegBase) {
|
|
if (!AM12.Base.Reg.getNode())
|
|
AM12.Base.Reg = CurDAG->getRegister(0, VT);
|
|
}
|
|
|
|
if (!AM12.IndexReg.getNode())
|
|
AM12.IndexReg = CurDAG->getRegister(0, VT);
|
|
|
|
getAddressOperands(AM12, Base, Disp, Index);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Returns true if the address can be represented by a base register plus
|
|
/// index register plus a signed 20-bit displacement [base + idx + imm].
|
|
bool SystemZDAGToDAGISel::SelectAddrRRI20(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index) {
|
|
SystemZRRIAddressMode AM;
|
|
bool Done = false;
|
|
|
|
if (!Addr.hasOneUse()) {
|
|
unsigned Opcode = Addr.getOpcode();
|
|
if (Opcode != ISD::Constant && Opcode != ISD::FrameIndex) {
|
|
// If we are able to fold N into addressing mode, then we'll allow it even
|
|
// if N has multiple uses. In general, addressing computation is used as
|
|
// addresses by all of its uses. But watch out for CopyToReg uses, that
|
|
// means the address computation is liveout. It will be computed by a LA
|
|
// so we want to avoid computing the address twice.
|
|
for (SDNode::use_iterator UI = Addr.getNode()->use_begin(),
|
|
UE = Addr.getNode()->use_end(); UI != UE; ++UI) {
|
|
if (UI->getOpcode() == ISD::CopyToReg) {
|
|
MatchAddressBase(Addr, AM);
|
|
Done = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!Done && MatchAddress(Addr, AM, /* is12Bit */ false))
|
|
return false;
|
|
|
|
DEBUG(errs() << "MatchAddress (final): "; AM.dump());
|
|
|
|
EVT VT = Addr.getValueType();
|
|
if (AM.BaseType == SystemZRRIAddressMode::RegBase) {
|
|
if (!AM.Base.Reg.getNode())
|
|
AM.Base.Reg = CurDAG->getRegister(0, VT);
|
|
}
|
|
|
|
if (!AM.IndexReg.getNode())
|
|
AM.IndexReg = CurDAG->getRegister(0, VT);
|
|
|
|
getAddressOperands(AM, Base, Disp, Index);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// SelectLAAddr - it calls SelectAddr and determines if the maximal addressing
|
|
/// mode it matches can be cost effectively emitted as an LA/LAY instruction.
|
|
bool SystemZDAGToDAGISel::SelectLAAddr(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index) {
|
|
SystemZRRIAddressMode AM;
|
|
|
|
if (MatchAddress(Addr, AM, false))
|
|
return false;
|
|
|
|
EVT VT = Addr.getValueType();
|
|
unsigned Complexity = 0;
|
|
if (AM.BaseType == SystemZRRIAddressMode::RegBase)
|
|
if (AM.Base.Reg.getNode())
|
|
Complexity = 1;
|
|
else
|
|
AM.Base.Reg = CurDAG->getRegister(0, VT);
|
|
else if (AM.BaseType == SystemZRRIAddressMode::FrameIndexBase)
|
|
Complexity = 4;
|
|
|
|
if (AM.IndexReg.getNode())
|
|
Complexity += 1;
|
|
else
|
|
AM.IndexReg = CurDAG->getRegister(0, VT);
|
|
|
|
if (AM.Disp && (AM.Base.Reg.getNode() || AM.IndexReg.getNode()))
|
|
Complexity += 1;
|
|
|
|
if (Complexity > 2) {
|
|
getAddressOperands(AM, Base, Disp, Index);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SystemZDAGToDAGISel::TryFoldLoad(SDNode *P, SDValue N,
|
|
SDValue &Base, SDValue &Disp, SDValue &Index) {
|
|
if (ISD::isNON_EXTLoad(N.getNode()) &&
|
|
IsLegalToFold(N, P, P))
|
|
return SelectAddrRRI20(P, N.getOperand(1), Base, Disp, Index);
|
|
return false;
|
|
}
|
|
|
|
SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) {
|
|
EVT NVT = Node->getValueType(0);
|
|
DebugLoc dl = Node->getDebugLoc();
|
|
unsigned Opcode = Node->getOpcode();
|
|
|
|
// Dump information about the Node being selected
|
|
DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n");
|
|
|
|
// If we have a custom node, we already have selected!
|
|
if (Node->isMachineOpcode()) {
|
|
DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
|
|
return NULL; // Already selected.
|
|
}
|
|
|
|
switch (Opcode) {
|
|
default: break;
|
|
case ISD::SDIVREM: {
|
|
unsigned Opc, MOpc;
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
|
|
EVT ResVT;
|
|
bool is32Bit = false;
|
|
switch (NVT.getSimpleVT().SimpleTy) {
|
|
default: assert(0 && "Unsupported VT!");
|
|
case MVT::i32:
|
|
Opc = SystemZ::SDIVREM32r; MOpc = SystemZ::SDIVREM32m;
|
|
ResVT = MVT::v2i64;
|
|
is32Bit = true;
|
|
break;
|
|
case MVT::i64:
|
|
Opc = SystemZ::SDIVREM64r; MOpc = SystemZ::SDIVREM64m;
|
|
ResVT = MVT::v2i64;
|
|
break;
|
|
}
|
|
|
|
SDValue Tmp0, Tmp1, Tmp2;
|
|
bool foldedLoad = TryFoldLoad(Node, N1, Tmp0, Tmp1, Tmp2);
|
|
|
|
// Prepare the dividend
|
|
SDNode *Dividend;
|
|
if (is32Bit)
|
|
Dividend = CurDAG->getMachineNode(SystemZ::MOVSX64rr32, dl, MVT::i64, N0);
|
|
else
|
|
Dividend = N0.getNode();
|
|
|
|
// Insert prepared dividend into suitable 'subreg'
|
|
SDNode *Tmp = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,
|
|
dl, ResVT);
|
|
Dividend =
|
|
CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, dl, ResVT,
|
|
SDValue(Tmp, 0), SDValue(Dividend, 0),
|
|
CurDAG->getTargetConstant(subreg_odd, MVT::i32));
|
|
|
|
SDNode *Result;
|
|
SDValue DivVal = SDValue(Dividend, 0);
|
|
if (foldedLoad) {
|
|
SDValue Ops[] = { DivVal, Tmp0, Tmp1, Tmp2, N1.getOperand(0) };
|
|
Result = CurDAG->getMachineNode(MOpc, dl, ResVT, MVT::Other,
|
|
Ops, array_lengthof(Ops));
|
|
// Update the chain.
|
|
ReplaceUses(N1.getValue(1), SDValue(Result, 1));
|
|
} else {
|
|
Result = CurDAG->getMachineNode(Opc, dl, ResVT, SDValue(Dividend, 0), N1);
|
|
}
|
|
|
|
// Copy the division (odd subreg) result, if it is needed.
|
|
if (!SDValue(Node, 0).use_empty()) {
|
|
unsigned SubRegIdx = (is32Bit ? subreg_odd32 : subreg_odd);
|
|
SDNode *Div = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
|
|
dl, NVT,
|
|
SDValue(Result, 0),
|
|
CurDAG->getTargetConstant(SubRegIdx,
|
|
MVT::i32));
|
|
|
|
ReplaceUses(SDValue(Node, 0), SDValue(Div, 0));
|
|
DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n");
|
|
}
|
|
|
|
// Copy the remainder (even subreg) result, if it is needed.
|
|
if (!SDValue(Node, 1).use_empty()) {
|
|
unsigned SubRegIdx = (is32Bit ? subreg_even32 : subreg_even);
|
|
SDNode *Rem = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
|
|
dl, NVT,
|
|
SDValue(Result, 0),
|
|
CurDAG->getTargetConstant(SubRegIdx,
|
|
MVT::i32));
|
|
|
|
ReplaceUses(SDValue(Node, 1), SDValue(Rem, 0));
|
|
DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n");
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
case ISD::UDIVREM: {
|
|
unsigned Opc, MOpc, ClrOpc;
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
EVT ResVT;
|
|
|
|
bool is32Bit = false;
|
|
switch (NVT.getSimpleVT().SimpleTy) {
|
|
default: assert(0 && "Unsupported VT!");
|
|
case MVT::i32:
|
|
Opc = SystemZ::UDIVREM32r; MOpc = SystemZ::UDIVREM32m;
|
|
ClrOpc = SystemZ::MOV64Pr0_even;
|
|
ResVT = MVT::v2i32;
|
|
is32Bit = true;
|
|
break;
|
|
case MVT::i64:
|
|
Opc = SystemZ::UDIVREM64r; MOpc = SystemZ::UDIVREM64m;
|
|
ClrOpc = SystemZ::MOV128r0_even;
|
|
ResVT = MVT::v2i64;
|
|
break;
|
|
}
|
|
|
|
SDValue Tmp0, Tmp1, Tmp2;
|
|
bool foldedLoad = TryFoldLoad(Node, N1, Tmp0, Tmp1, Tmp2);
|
|
|
|
// Prepare the dividend
|
|
SDNode *Dividend = N0.getNode();
|
|
|
|
// Insert prepared dividend into suitable 'subreg'
|
|
SDNode *Tmp = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,
|
|
dl, ResVT);
|
|
{
|
|
unsigned SubRegIdx = (is32Bit ? subreg_odd32 : subreg_odd);
|
|
Dividend =
|
|
CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, dl, ResVT,
|
|
SDValue(Tmp, 0), SDValue(Dividend, 0),
|
|
CurDAG->getTargetConstant(SubRegIdx, MVT::i32));
|
|
}
|
|
|
|
// Zero out even subreg
|
|
Dividend = CurDAG->getMachineNode(ClrOpc, dl, ResVT, SDValue(Dividend, 0));
|
|
|
|
SDValue DivVal = SDValue(Dividend, 0);
|
|
SDNode *Result;
|
|
if (foldedLoad) {
|
|
SDValue Ops[] = { DivVal, Tmp0, Tmp1, Tmp2, N1.getOperand(0) };
|
|
Result = CurDAG->getMachineNode(MOpc, dl, ResVT, MVT::Other,
|
|
Ops, array_lengthof(Ops));
|
|
// Update the chain.
|
|
ReplaceUses(N1.getValue(1), SDValue(Result, 1));
|
|
} else {
|
|
Result = CurDAG->getMachineNode(Opc, dl, ResVT, DivVal, N1);
|
|
}
|
|
|
|
// Copy the division (odd subreg) result, if it is needed.
|
|
if (!SDValue(Node, 0).use_empty()) {
|
|
unsigned SubRegIdx = (is32Bit ? subreg_odd32 : subreg_odd);
|
|
SDNode *Div = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
|
|
dl, NVT,
|
|
SDValue(Result, 0),
|
|
CurDAG->getTargetConstant(SubRegIdx,
|
|
MVT::i32));
|
|
ReplaceUses(SDValue(Node, 0), SDValue(Div, 0));
|
|
DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n");
|
|
}
|
|
|
|
// Copy the remainder (even subreg) result, if it is needed.
|
|
if (!SDValue(Node, 1).use_empty()) {
|
|
unsigned SubRegIdx = (is32Bit ? subreg_even32 : subreg_even);
|
|
SDNode *Rem = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
|
|
dl, NVT,
|
|
SDValue(Result, 0),
|
|
CurDAG->getTargetConstant(SubRegIdx,
|
|
MVT::i32));
|
|
ReplaceUses(SDValue(Node, 1), SDValue(Rem, 0));
|
|
DEBUG(errs() << "=> "; Result->dump(CurDAG); errs() << "\n");
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Select the default instruction
|
|
SDNode *ResNode = SelectCode(Node);
|
|
|
|
DEBUG(errs() << "=> ";
|
|
if (ResNode == NULL || ResNode == Node)
|
|
Node->dump(CurDAG);
|
|
else
|
|
ResNode->dump(CurDAG);
|
|
errs() << "\n";
|
|
);
|
|
return ResNode;
|
|
}
|