mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-14 16:33:28 +00:00
Do some heroic rri address matching (shamelessly stolen from x86 backend). Not tested though.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75929 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4cad7d29fc
commit
3360da9772
@ -52,6 +52,8 @@ namespace {
|
||||
const char* Modifier = 0);
|
||||
void printRIAddrOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier = 0);
|
||||
void printRRIAddrOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier = 0);
|
||||
bool printInstruction(const MachineInstr *MI); // autogenerated.
|
||||
void printMachineInstruction(const MachineInstr * MI);
|
||||
|
||||
@ -196,10 +198,31 @@ void SystemZAsmPrinter::printRIAddrOperand(const MachineInstr *MI, int OpNum,
|
||||
printOperand(MI, OpNum+1);
|
||||
|
||||
// Print base operand (if any)
|
||||
if (!(Base.isReg() && Base.getReg() == SystemZ::R0D)) {
|
||||
if (Base.getReg()) {
|
||||
O << '(';
|
||||
printOperand(MI, OpNum);
|
||||
O << ')';
|
||||
}
|
||||
}
|
||||
|
||||
void SystemZAsmPrinter::printRRIAddrOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier) {
|
||||
const MachineOperand &Base = MI->getOperand(OpNum);
|
||||
const MachineOperand &Index = MI->getOperand(OpNum);
|
||||
|
||||
// Print displacement operand.
|
||||
printOperand(MI, OpNum+2);
|
||||
|
||||
// Print base operand (if any)
|
||||
if (Base.getReg()) {
|
||||
O << '(';
|
||||
printOperand(MI, OpNum);
|
||||
if (Index.getReg()) {
|
||||
O << ',';
|
||||
printOperand(MI, OpNum+1);
|
||||
}
|
||||
O << ')';
|
||||
} else
|
||||
assert(!Index.getReg() && "Should allocate base register first!");
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,44 @@
|
||||
#include "llvm/Support/Debug.h"
|
||||
using namespace llvm;
|
||||
|
||||
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;
|
||||
int32_t Disp;
|
||||
|
||||
SystemZRRIAddressMode()
|
||||
: BaseType(RegBase), IndexReg(), Disp(0) {
|
||||
}
|
||||
|
||||
void dump() {
|
||||
cerr << "SystemZRRIAddressMode " << this << "\n";
|
||||
if (BaseType == RegBase) {
|
||||
cerr << "Base.Reg ";
|
||||
if (Base.Reg.getNode() != 0) Base.Reg.getNode()->dump();
|
||||
else cerr << "nul";
|
||||
} else {
|
||||
cerr << " Base.FrameIndex " << Base.FrameIndex << "\n";
|
||||
}
|
||||
cerr << "IndexReg ";
|
||||
if (IndexReg.getNode() != 0) IndexReg.getNode()->dump();
|
||||
else cerr << "nul";
|
||||
cerr << " Disp " << Disp << "\n";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// SystemZDAGToDAGISel - SystemZ specific code to select SystemZ machine
|
||||
/// instructions for SelectionDAG operations.
|
||||
///
|
||||
@ -66,9 +104,13 @@ namespace {
|
||||
#include "SystemZGenDAGISel.inc"
|
||||
|
||||
private:
|
||||
bool SelectAddrRRI(SDValue Op, SDValue Addr,
|
||||
SDValue &Base, SDValue &Index, SDValue &Disp);
|
||||
SDNode *Select(SDValue Op);
|
||||
bool SelectAddrRI(const SDValue& Op, SDValue& Addr,
|
||||
SDValue &Base, SDValue &Disp);
|
||||
bool MatchAddress(SDValue N, SystemZRRIAddressMode &AM, unsigned Depth = 0);
|
||||
bool MatchAddressBase(SDValue N, SystemZRRIAddressMode &AM);
|
||||
|
||||
#ifndef NDEBUG
|
||||
unsigned Indent;
|
||||
@ -88,20 +130,19 @@ FunctionPass *llvm::createSystemZISelDag(SystemZTargetMachine &TM,
|
||||
/// 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, int32_t &Imm) {
|
||||
if (Val >= -524288 && Val <= 524287) {
|
||||
Imm = (int32_t)Val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isImmSExt20(SDNode *N, int32_t &Imm) {
|
||||
if (N->getOpcode() != ISD::Constant)
|
||||
return false;
|
||||
|
||||
Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
|
||||
|
||||
if (Imm >= -524288 && Imm <= 524287) {
|
||||
if (N->getValueType(0) == MVT::i32)
|
||||
return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
|
||||
else
|
||||
return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue();
|
||||
}
|
||||
|
||||
return false;
|
||||
return isImmSExt20(cast<ConstantSDNode>(N)->getSExtValue(), Imm);
|
||||
}
|
||||
|
||||
static bool isImmSExt20(SDValue Op, int32_t &Imm) {
|
||||
@ -156,7 +197,7 @@ bool SystemZDAGToDAGISel::SelectAddrRI(const SDValue& Op, SDValue& Addr,
|
||||
int32_t Imm;
|
||||
if (isImmSExt20(CN, Imm)) {
|
||||
Disp = CurDAG->getTargetConstant(Imm, MVT::i32);
|
||||
Base = CurDAG->getRegister(SystemZ::R0D, MVT::i64);
|
||||
Base = CurDAG->getRegister(0, VT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -169,6 +210,184 @@ bool SystemZDAGToDAGISel::SelectAddrRI(const SDValue& Op, SDValue& Addr,
|
||||
return true; // [r+0]
|
||||
}
|
||||
|
||||
/// 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,
|
||||
unsigned Depth) {
|
||||
DebugLoc dl = N.getDebugLoc();
|
||||
DOUT << "MatchAddress: "; DEBUG(AM.dump());
|
||||
// Limit recursion.
|
||||
if (Depth > 5)
|
||||
return MatchAddressBase(N, AM);
|
||||
|
||||
switch (N.getOpcode()) {
|
||||
default: break;
|
||||
case ISD::Constant: {
|
||||
uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
|
||||
int32_t Imm;
|
||||
if (isImmSExt20(AM.Disp + Val, Imm)) {
|
||||
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, Depth+1)) {
|
||||
AM = Backup;
|
||||
break;
|
||||
}
|
||||
// Test if the index field is free for use.
|
||||
if (AM.IndexReg.getNode()) {
|
||||
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, Depth+1) &&
|
||||
!MatchAddress(N.getNode()->getOperand(1), AM, Depth+1))
|
||||
return false;
|
||||
AM = Backup;
|
||||
if (!MatchAddress(N.getNode()->getOperand(1), AM, Depth+1) &&
|
||||
!MatchAddress(N.getNode()->getOperand(0), AM, 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.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;
|
||||
uint64_t Offset = CN->getSExtValue();
|
||||
int32_t Imm;
|
||||
// Start with the LHS as an addr mode.
|
||||
if (!MatchAddress(N.getOperand(0), AM, Depth+1) &&
|
||||
// The resultant disp must fit in 20-bits.
|
||||
isImmSExt20(AM.Disp + Offset, Imm) &&
|
||||
// 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 scale index register is set.
|
||||
if (AM.IndexReg.getNode() == 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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::SelectAddrRRI(SDValue Op, SDValue Addr,
|
||||
SDValue &Base, SDValue &Index, SDValue &Disp) {
|
||||
SystemZRRIAddressMode AM;
|
||||
bool Done = false;
|
||||
|
||||
// FIXME: Should we better use lay instruction for non-single uses?
|
||||
|
||||
if (!Done && MatchAddress(Addr, AM))
|
||||
return false;
|
||||
|
||||
MVT 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);
|
||||
|
||||
if (AM.BaseType == SystemZRRIAddressMode::RegBase)
|
||||
Base = AM.Base.Reg;
|
||||
else
|
||||
Base = CurDAG->getTargetFrameIndex(AM.Base.FrameIndex, TLI.getPointerTy());
|
||||
Index = AM.IndexReg;
|
||||
Disp = Disp = CurDAG->getTargetConstant(AM.Disp, MVT::i32);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// InstructionSelect - This callback is invoked by
|
||||
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
||||
|
@ -129,6 +129,13 @@ def riaddr : Operand<i64>,
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// rriaddr := reg + reg + imm
|
||||
def rriaddr : Operand<i64>,
|
||||
ComplexPattern<i64, 3, "SelectAddrRRI", []> {
|
||||
let PrintMethod = "printRRIAddrOperand";
|
||||
let MIOperandInfo = (ops ADDR64:$base, ADDR64:$index, i32imm:$disp);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Control Flow Instructions...
|
||||
//
|
||||
@ -191,6 +198,13 @@ def MOV64rihi32 : Pseudo<(outs GR64:$dst), (ins i64imm:$src),
|
||||
[(set GR64:$dst, i64hi32:$src)]>;
|
||||
}
|
||||
|
||||
let canFoldAsLoad = 1, isReMaterializable = 1, mayHaveSideEffects = 1 in {
|
||||
def MOV64rm : Pseudo<(outs GR64:$dst), (ins rriaddr:$src),
|
||||
"lgr\t{$dst, $src}",
|
||||
[(set GR64:$dst, (load rriaddr:$src))]>;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Arithmetic Instructions
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user