2005-10-20 00:29:02 +00:00
|
|
|
//===-- AlphaISelDAGToDAG.cpp - Alpha pattern matching inst selector ------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-10-20 00:29:02 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines a pattern matching instruction selector for Alpha,
|
|
|
|
// converting from a legalized dag to a Alpha dag.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Alpha.h"
|
|
|
|
#include "AlphaTargetMachine.h"
|
|
|
|
#include "AlphaISelLowering.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2005-11-30 07:19:56 +00:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2005-10-20 00:29:02 +00:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2007-12-31 04:13:23 +00:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2005-10-20 00:29:02 +00:00
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
#include "llvm/Constants.h"
|
2007-01-19 21:13:56 +00:00
|
|
|
#include "llvm/DerivedTypes.h"
|
2005-10-20 00:29:02 +00:00
|
|
|
#include "llvm/GlobalValue.h"
|
2006-03-25 06:47:10 +00:00
|
|
|
#include "llvm/Intrinsics.h"
|
2008-02-03 05:43:57 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2005-10-20 00:29:02 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
2005-10-22 22:06:58 +00:00
|
|
|
#include <algorithm>
|
2006-08-07 22:28:20 +00:00
|
|
|
#include <queue>
|
2006-02-05 06:46:41 +00:00
|
|
|
#include <set>
|
2005-10-20 00:29:02 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
/// AlphaDAGToDAGISel - Alpha specific code to select Alpha machine
|
|
|
|
/// instructions for SelectionDAG operations.
|
|
|
|
class AlphaDAGToDAGISel : public SelectionDAGISel {
|
|
|
|
AlphaTargetLowering AlphaLowering;
|
|
|
|
|
2005-12-30 02:30:02 +00:00
|
|
|
static const int64_t IMM_LOW = -32768;
|
|
|
|
static const int64_t IMM_HIGH = 32767;
|
|
|
|
static const int64_t IMM_MULT = 65536;
|
2006-01-01 22:16:14 +00:00
|
|
|
static const int64_t IMM_FULLHIGH = IMM_HIGH + IMM_HIGH * IMM_MULT;
|
|
|
|
static const int64_t IMM_FULLLOW = IMM_LOW + IMM_LOW * IMM_MULT;
|
|
|
|
|
|
|
|
static int64_t get_ldah16(int64_t x) {
|
|
|
|
int64_t y = x / IMM_MULT;
|
|
|
|
if (x % IMM_MULT > IMM_HIGH)
|
2007-04-16 18:10:23 +00:00
|
|
|
++y;
|
2006-01-01 22:16:14 +00:00
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t get_lda16(int64_t x) {
|
|
|
|
return x - get_ldah16(x) * IMM_MULT;
|
|
|
|
}
|
|
|
|
|
Use cute tblgen tricks to make zap handling more powerful. Specifically,
when the dag combiner simplifies an and mask, notice this and allow those bits
to be missing from the zap mask.
This compiles Alpha/zapnot4.ll into:
sll $16,3,$0
zapnot $0,3,$0
ret $31,($26),1
instead of:
ldah $0,1($31)
lda $0,-8($0)
sll $16,3,$1
and $1,$0,$0
ret $31,($26),1
It would be *really* nice to replace the hunk of code in the
AlphaISelDAGToDAG.cpp file that matches (and (srl (x, C), c2) into
(SRL (ZAPNOTi)) with a similar pattern, but I've spent enough time poking
at alpha. Make andrew will do this.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30875 91177308-0d34-0410-b5e6-96231b3b80d8
2006-10-11 05:13:56 +00:00
|
|
|
/// get_zapImm - Return a zap mask if X is a valid immediate for a zapnot
|
|
|
|
/// instruction (if not, return 0). Note that this code accepts partial
|
|
|
|
/// zap masks. For example (and LHS, 1) is a valid zap, as long we know
|
|
|
|
/// that the bits 1-7 of LHS are already zero. If LHS is non-null, we are
|
|
|
|
/// in checking mode. If LHS is null, we assume that the mask has already
|
|
|
|
/// been validated before.
|
|
|
|
uint64_t get_zapImm(SDOperand LHS, uint64_t Constant) {
|
|
|
|
uint64_t BitsToCheck = 0;
|
|
|
|
unsigned Result = 0;
|
|
|
|
for (unsigned i = 0; i != 8; ++i) {
|
|
|
|
if (((Constant >> 8*i) & 0xFF) == 0) {
|
|
|
|
// nothing to do.
|
|
|
|
} else {
|
|
|
|
Result |= 1 << i;
|
|
|
|
if (((Constant >> 8*i) & 0xFF) == 0xFF) {
|
|
|
|
// If the entire byte is set, zapnot the byte.
|
|
|
|
} else if (LHS.Val == 0) {
|
|
|
|
// Otherwise, if the mask was previously validated, we know its okay
|
|
|
|
// to zapnot this entire byte even though all the bits aren't set.
|
|
|
|
} else {
|
|
|
|
// Otherwise we don't know that the it's okay to zapnot this entire
|
|
|
|
// byte. Only do this iff we can prove that the missing bits are
|
|
|
|
// already null, so the bytezap doesn't need to really null them.
|
|
|
|
BitsToCheck |= ~Constant & (0xFF << 8*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there are missing bits in a byte (for example, X & 0xEF00), check to
|
|
|
|
// see if the missing bits (0x1000) are already known zero if not, the zap
|
|
|
|
// isn't okay to do, as it won't clear all the required bits.
|
|
|
|
if (BitsToCheck &&
|
2008-02-25 21:11:39 +00:00
|
|
|
!CurDAG->MaskedValueIsZero(LHS,
|
|
|
|
APInt(LHS.getValueSizeInBits(),
|
|
|
|
BitsToCheck)))
|
Use cute tblgen tricks to make zap handling more powerful. Specifically,
when the dag combiner simplifies an and mask, notice this and allow those bits
to be missing from the zap mask.
This compiles Alpha/zapnot4.ll into:
sll $16,3,$0
zapnot $0,3,$0
ret $31,($26),1
instead of:
ldah $0,1($31)
lda $0,-8($0)
sll $16,3,$1
and $1,$0,$0
ret $31,($26),1
It would be *really* nice to replace the hunk of code in the
AlphaISelDAGToDAG.cpp file that matches (and (srl (x, C), c2) into
(SRL (ZAPNOTi)) with a similar pattern, but I've spent enough time poking
at alpha. Make andrew will do this.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30875 91177308-0d34-0410-b5e6-96231b3b80d8
2006-10-11 05:13:56 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2006-01-01 22:16:14 +00:00
|
|
|
static uint64_t get_zapImm(uint64_t x) {
|
Use cute tblgen tricks to make zap handling more powerful. Specifically,
when the dag combiner simplifies an and mask, notice this and allow those bits
to be missing from the zap mask.
This compiles Alpha/zapnot4.ll into:
sll $16,3,$0
zapnot $0,3,$0
ret $31,($26),1
instead of:
ldah $0,1($31)
lda $0,-8($0)
sll $16,3,$1
and $1,$0,$0
ret $31,($26),1
It would be *really* nice to replace the hunk of code in the
AlphaISelDAGToDAG.cpp file that matches (and (srl (x, C), c2) into
(SRL (ZAPNOTi)) with a similar pattern, but I've spent enough time poking
at alpha. Make andrew will do this.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30875 91177308-0d34-0410-b5e6-96231b3b80d8
2006-10-11 05:13:56 +00:00
|
|
|
unsigned build = 0;
|
|
|
|
for(int i = 0; i != 8; ++i) {
|
|
|
|
if ((x & 0x00FF) == 0x00FF)
|
|
|
|
build |= 1 << i;
|
|
|
|
else if ((x & 0x00FF) != 0)
|
|
|
|
return 0;
|
|
|
|
x >>= 8;
|
|
|
|
}
|
2006-01-02 21:15:53 +00:00
|
|
|
return build;
|
2006-01-01 22:16:14 +00:00
|
|
|
}
|
Use cute tblgen tricks to make zap handling more powerful. Specifically,
when the dag combiner simplifies an and mask, notice this and allow those bits
to be missing from the zap mask.
This compiles Alpha/zapnot4.ll into:
sll $16,3,$0
zapnot $0,3,$0
ret $31,($26),1
instead of:
ldah $0,1($31)
lda $0,-8($0)
sll $16,3,$1
and $1,$0,$0
ret $31,($26),1
It would be *really* nice to replace the hunk of code in the
AlphaISelDAGToDAG.cpp file that matches (and (srl (x, C), c2) into
(SRL (ZAPNOTi)) with a similar pattern, but I've spent enough time poking
at alpha. Make andrew will do this.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30875 91177308-0d34-0410-b5e6-96231b3b80d8
2006-10-11 05:13:56 +00:00
|
|
|
|
|
|
|
|
2006-04-03 03:18:59 +00:00
|
|
|
static uint64_t getNearPower2(uint64_t x) {
|
|
|
|
if (!x) return 0;
|
|
|
|
unsigned at = CountLeadingZeros_64(x);
|
|
|
|
uint64_t complow = 1 << (63 - at);
|
|
|
|
uint64_t comphigh = 1 << (64 - at);
|
2006-12-07 22:21:48 +00:00
|
|
|
//cerr << x << ":" << complow << ":" << comphigh << "\n";
|
2006-04-03 04:19:17 +00:00
|
|
|
if (abs(complow - x) <= abs(comphigh - x))
|
2006-04-03 03:18:59 +00:00
|
|
|
return complow;
|
|
|
|
else
|
|
|
|
return comphigh;
|
|
|
|
}
|
|
|
|
|
2006-10-31 19:52:12 +00:00
|
|
|
static bool chkRemNearPower2(uint64_t x, uint64_t r, bool swap) {
|
|
|
|
uint64_t y = getNearPower2(x);
|
|
|
|
if (swap)
|
|
|
|
return (y - x) == r;
|
|
|
|
else
|
|
|
|
return (x - y) == r;
|
|
|
|
}
|
|
|
|
|
2006-01-01 22:16:14 +00:00
|
|
|
static bool isFPZ(SDOperand N) {
|
|
|
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N);
|
2007-08-31 04:03:46 +00:00
|
|
|
return (CN && (CN->getValueAPF().isZero()));
|
2006-01-01 22:16:14 +00:00
|
|
|
}
|
|
|
|
static bool isFPZn(SDOperand N) {
|
|
|
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N);
|
2007-08-31 04:03:46 +00:00
|
|
|
return (CN && CN->getValueAPF().isNegZero());
|
2006-01-01 22:16:14 +00:00
|
|
|
}
|
|
|
|
static bool isFPZp(SDOperand N) {
|
|
|
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N);
|
2007-08-31 04:03:46 +00:00
|
|
|
return (CN && CN->getValueAPF().isPosZero());
|
2006-01-01 22:16:14 +00:00
|
|
|
}
|
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
public:
|
|
|
|
AlphaDAGToDAGISel(TargetMachine &TM)
|
2006-10-11 04:29:42 +00:00
|
|
|
: SelectionDAGISel(AlphaLowering),
|
2007-04-16 18:10:23 +00:00
|
|
|
AlphaLowering(*(AlphaTargetLowering*)(TM.getTargetLowering()))
|
2005-12-30 02:30:02 +00:00
|
|
|
{}
|
2005-10-20 00:29:02 +00:00
|
|
|
|
|
|
|
/// getI64Imm - Return a target constant with the specified value, of type
|
|
|
|
/// i64.
|
2005-10-22 22:06:58 +00:00
|
|
|
inline SDOperand getI64Imm(int64_t Imm) {
|
2005-10-20 00:29:02 +00:00
|
|
|
return CurDAG->getTargetConstant(Imm, MVT::i64);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select - Convert the specified operand from a target-independent to a
|
|
|
|
// target-specific node if it hasn't already been changed.
|
2006-08-26 05:34:46 +00:00
|
|
|
SDNode *Select(SDOperand Op);
|
2005-10-20 00:29:02 +00:00
|
|
|
|
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
|
|
|
virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
|
|
|
|
|
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "Alpha DAG->DAG Pattern Instruction Selection";
|
|
|
|
}
|
|
|
|
|
2006-06-21 15:42:36 +00:00
|
|
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
|
|
|
/// inline asm expressions.
|
|
|
|
virtual bool SelectInlineAsmMemoryOperand(const SDOperand &Op,
|
|
|
|
char ConstraintCode,
|
|
|
|
std::vector<SDOperand> &OutOps,
|
|
|
|
SelectionDAG &DAG) {
|
|
|
|
SDOperand Op0;
|
|
|
|
switch (ConstraintCode) {
|
|
|
|
default: return true;
|
|
|
|
case 'm': // memory
|
2006-08-26 01:07:58 +00:00
|
|
|
Op0 = Op;
|
2007-04-16 18:10:23 +00:00
|
|
|
AddToISelQueue(Op0);
|
2006-06-21 15:42:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
OutOps.push_back(Op0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
// Include the pieces autogenerated from the target description.
|
|
|
|
#include "AlphaGenDAGISel.inc"
|
|
|
|
|
|
|
|
private:
|
2005-10-22 22:06:58 +00:00
|
|
|
SDOperand getGlobalBaseReg();
|
2006-06-13 18:27:39 +00:00
|
|
|
SDOperand getGlobalRetAddr();
|
2006-08-26 05:34:46 +00:00
|
|
|
void SelectCALL(SDOperand Op);
|
2005-10-22 22:06:58 +00:00
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2005-10-22 22:06:58 +00:00
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
|
|
|
/// GOT address into a register.
|
|
|
|
///
|
|
|
|
SDOperand AlphaDAGToDAGISel::getGlobalBaseReg() {
|
2006-10-11 16:24:51 +00:00
|
|
|
unsigned GP = 0;
|
2007-12-31 04:13:23 +00:00
|
|
|
for(MachineRegisterInfo::livein_iterator ii = RegInfo->livein_begin(),
|
|
|
|
ee = RegInfo->livein_end(); ii != ee; ++ii)
|
2006-10-11 16:24:51 +00:00
|
|
|
if (ii->first == Alpha::R29) {
|
|
|
|
GP = ii->second;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
assert(GP && "GOT PTR not in liveins");
|
2005-12-01 01:53:10 +00:00
|
|
|
return CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
|
2006-10-11 16:24:51 +00:00
|
|
|
GP, MVT::i64);
|
2005-12-01 01:53:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getRASaveReg - Grab the return address
|
|
|
|
///
|
2006-06-13 18:27:39 +00:00
|
|
|
SDOperand AlphaDAGToDAGISel::getGlobalRetAddr() {
|
2006-10-11 16:24:51 +00:00
|
|
|
unsigned RA = 0;
|
2007-12-31 04:13:23 +00:00
|
|
|
for(MachineRegisterInfo::livein_iterator ii = RegInfo->livein_begin(),
|
|
|
|
ee = RegInfo->livein_end(); ii != ee; ++ii)
|
2006-10-11 16:24:51 +00:00
|
|
|
if (ii->first == Alpha::R26) {
|
|
|
|
RA = ii->second;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
assert(RA && "RA PTR not in liveins");
|
2005-12-01 01:53:10 +00:00
|
|
|
return CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
|
2006-10-11 16:24:51 +00:00
|
|
|
RA, MVT::i64);
|
2005-10-22 22:06:58 +00:00
|
|
|
}
|
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
|
|
|
void AlphaDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) {
|
|
|
|
DEBUG(BB->dump());
|
|
|
|
|
|
|
|
// Select target instructions for the DAG.
|
2006-02-05 06:46:41 +00:00
|
|
|
DAG.setRoot(SelectRoot(DAG.getRoot()));
|
2005-10-20 00:29:02 +00:00
|
|
|
DAG.RemoveDeadNodes();
|
|
|
|
|
|
|
|
// Emit machine code to BB.
|
|
|
|
ScheduleAndEmitDAG(DAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select - Convert the specified operand from a target-independent to a
|
|
|
|
// target-specific node if it hasn't already been changed.
|
2006-08-26 05:34:46 +00:00
|
|
|
SDNode *AlphaDAGToDAGISel::Select(SDOperand Op) {
|
2005-10-20 00:29:02 +00:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
if (N->getOpcode() >= ISD::BUILTIN_OP_END &&
|
2006-02-09 00:37:58 +00:00
|
|
|
N->getOpcode() < AlphaISD::FIRST_NUMBER) {
|
2006-08-11 09:08:15 +00:00
|
|
|
return NULL; // Already selected.
|
2006-02-09 00:37:58 +00:00
|
|
|
}
|
2005-10-20 00:29:02 +00:00
|
|
|
|
|
|
|
switch (N->getOpcode()) {
|
|
|
|
default: break;
|
2006-02-09 00:37:58 +00:00
|
|
|
case AlphaISD::CALL:
|
2006-08-26 05:34:46 +00:00
|
|
|
SelectCALL(Op);
|
2006-08-11 09:08:15 +00:00
|
|
|
return NULL;
|
2005-10-22 22:06:58 +00:00
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
case ISD::FrameIndex: {
|
2005-11-22 04:20:06 +00:00
|
|
|
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
2006-08-16 07:30:09 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, Alpha::LDA, MVT::i64,
|
|
|
|
CurDAG->getTargetFrameIndex(FI, MVT::i32),
|
2006-08-26 08:00:10 +00:00
|
|
|
getI64Imm(0));
|
2005-10-20 00:29:02 +00:00
|
|
|
}
|
2006-10-11 04:29:42 +00:00
|
|
|
case ISD::GLOBAL_OFFSET_TABLE: {
|
2006-08-26 05:34:46 +00:00
|
|
|
SDOperand Result = getGlobalBaseReg();
|
2006-08-07 22:28:20 +00:00
|
|
|
ReplaceUses(Op, Result);
|
2006-08-11 09:08:15 +00:00
|
|
|
return NULL;
|
2006-08-26 05:34:46 +00:00
|
|
|
}
|
|
|
|
case AlphaISD::GlobalRetAddr: {
|
|
|
|
SDOperand Result = getGlobalRetAddr();
|
2006-08-07 22:28:20 +00:00
|
|
|
ReplaceUses(Op, Result);
|
2006-08-11 09:08:15 +00:00
|
|
|
return NULL;
|
2006-08-26 05:34:46 +00:00
|
|
|
}
|
2005-12-24 05:36:33 +00:00
|
|
|
|
2005-12-25 01:34:27 +00:00
|
|
|
case AlphaISD::DivCall: {
|
|
|
|
SDOperand Chain = CurDAG->getEntryNode();
|
2006-08-26 01:07:58 +00:00
|
|
|
SDOperand N0 = Op.getOperand(0);
|
|
|
|
SDOperand N1 = Op.getOperand(1);
|
|
|
|
SDOperand N2 = Op.getOperand(2);
|
|
|
|
AddToISelQueue(N0);
|
|
|
|
AddToISelQueue(N1);
|
|
|
|
AddToISelQueue(N2);
|
2006-02-09 00:37:58 +00:00
|
|
|
Chain = CurDAG->getCopyToReg(Chain, Alpha::R24, N1,
|
2007-04-16 18:10:23 +00:00
|
|
|
SDOperand(0,0));
|
2006-02-09 00:37:58 +00:00
|
|
|
Chain = CurDAG->getCopyToReg(Chain, Alpha::R25, N2,
|
2007-04-16 18:10:23 +00:00
|
|
|
Chain.getValue(1));
|
2006-02-09 00:37:58 +00:00
|
|
|
Chain = CurDAG->getCopyToReg(Chain, Alpha::R27, N0,
|
2007-04-16 18:10:23 +00:00
|
|
|
Chain.getValue(1));
|
2006-02-09 07:17:49 +00:00
|
|
|
SDNode *CNode =
|
|
|
|
CurDAG->getTargetNode(Alpha::JSRs, MVT::Other, MVT::Flag,
|
|
|
|
Chain, Chain.getValue(1));
|
2005-12-25 01:34:27 +00:00
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, Alpha::R27, MVT::i64,
|
2007-04-16 18:10:23 +00:00
|
|
|
SDOperand(CNode, 1));
|
2006-10-31 23:46:56 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, Alpha::BISr, MVT::i64, Chain, Chain);
|
2005-10-20 00:29:02 +00:00
|
|
|
}
|
|
|
|
|
2006-01-16 21:22:38 +00:00
|
|
|
case ISD::READCYCLECOUNTER: {
|
2006-08-26 01:07:58 +00:00
|
|
|
SDOperand Chain = N->getOperand(0);
|
|
|
|
AddToISelQueue(Chain); //Select chain
|
2006-08-26 05:34:46 +00:00
|
|
|
return CurDAG->getTargetNode(Alpha::RPCC, MVT::i64, MVT::Other,
|
|
|
|
Chain);
|
2006-01-16 21:22:38 +00:00
|
|
|
}
|
|
|
|
|
2005-11-22 04:20:06 +00:00
|
|
|
case ISD::Constant: {
|
2005-12-30 02:30:02 +00:00
|
|
|
uint64_t uval = cast<ConstantSDNode>(N)->getValue();
|
2006-01-06 19:41:51 +00:00
|
|
|
|
2006-02-09 00:37:58 +00:00
|
|
|
if (uval == 0) {
|
2006-08-26 05:34:46 +00:00
|
|
|
SDOperand Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
|
|
|
|
Alpha::R31, MVT::i64);
|
2006-08-07 22:28:20 +00:00
|
|
|
ReplaceUses(Op, Result);
|
2006-08-11 09:08:15 +00:00
|
|
|
return NULL;
|
2006-02-09 00:37:58 +00:00
|
|
|
}
|
2006-01-06 19:41:51 +00:00
|
|
|
|
2005-12-30 02:30:02 +00:00
|
|
|
int64_t val = (int64_t)uval;
|
|
|
|
int32_t val32 = (int32_t)val;
|
|
|
|
if (val <= IMM_HIGH + IMM_HIGH * IMM_MULT &&
|
2007-04-16 18:10:23 +00:00
|
|
|
val >= IMM_LOW + IMM_LOW * IMM_MULT)
|
2005-12-30 02:30:02 +00:00
|
|
|
break; //(LDAH (LDA))
|
|
|
|
if ((uval >> 32) == 0 && //empty upper bits
|
2007-04-16 18:10:23 +00:00
|
|
|
val32 <= IMM_HIGH + IMM_HIGH * IMM_MULT)
|
|
|
|
// val32 >= IMM_LOW + IMM_LOW * IMM_MULT) //always true
|
2005-12-30 02:30:02 +00:00
|
|
|
break; //(zext (LDAH (LDA)))
|
|
|
|
//Else use the constant pool
|
2006-12-31 05:55:36 +00:00
|
|
|
ConstantInt *C = ConstantInt::get(Type::Int64Ty, uval);
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand CPI = CurDAG->getTargetConstantPool(C, MVT::i64);
|
|
|
|
SDNode *Tmp = CurDAG->getTargetNode(Alpha::LDAHr, MVT::i64, CPI,
|
|
|
|
getGlobalBaseReg());
|
2006-08-16 07:30:09 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, Alpha::LDQr, MVT::i64, MVT::Other,
|
2007-04-16 18:10:23 +00:00
|
|
|
CPI, SDOperand(Tmp, 0), CurDAG->getEntryNode());
|
2005-11-22 04:20:06 +00:00
|
|
|
}
|
2006-01-29 06:25:22 +00:00
|
|
|
case ISD::TargetConstantFP: {
|
|
|
|
ConstantFPSDNode *CN = cast<ConstantFPSDNode>(N);
|
|
|
|
bool isDouble = N->getValueType(0) == MVT::f64;
|
|
|
|
MVT::ValueType T = isDouble ? MVT::f64 : MVT::f32;
|
2007-08-31 04:03:46 +00:00
|
|
|
if (CN->getValueAPF().isPosZero()) {
|
2006-08-16 07:30:09 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, isDouble ? Alpha::CPYST : Alpha::CPYSS,
|
|
|
|
T, CurDAG->getRegister(Alpha::F31, T),
|
2006-08-26 08:00:10 +00:00
|
|
|
CurDAG->getRegister(Alpha::F31, T));
|
2007-08-31 04:03:46 +00:00
|
|
|
} else if (CN->getValueAPF().isNegZero()) {
|
2006-08-16 07:30:09 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, isDouble ? Alpha::CPYSNT : Alpha::CPYSNS,
|
|
|
|
T, CurDAG->getRegister(Alpha::F31, T),
|
2006-08-26 08:00:10 +00:00
|
|
|
CurDAG->getRegister(Alpha::F31, T));
|
2006-01-29 06:25:22 +00:00
|
|
|
} else {
|
|
|
|
abort();
|
2005-11-22 04:20:06 +00:00
|
|
|
}
|
2006-01-29 06:25:22 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-11-30 07:19:56 +00:00
|
|
|
|
|
|
|
case ISD::SETCC:
|
|
|
|
if (MVT::isFloatingPoint(N->getOperand(0).Val->getValueType(0))) {
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
|
2007-01-24 18:43:14 +00:00
|
|
|
|
|
|
|
unsigned Opc = Alpha::WTF;
|
2005-11-30 07:19:56 +00:00
|
|
|
bool rev = false;
|
2007-01-24 18:43:14 +00:00
|
|
|
bool inv = false;
|
2005-11-30 07:19:56 +00:00
|
|
|
switch(CC) {
|
2007-06-19 14:13:56 +00:00
|
|
|
default: DEBUG(N->dump(CurDAG)); assert(0 && "Unknown FP comparison!");
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETEQ: case ISD::SETOEQ: case ISD::SETUEQ:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTEQ; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETLT: case ISD::SETOLT: case ISD::SETULT:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTLT; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETLE: case ISD::SETOLE: case ISD::SETULE:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTLE; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETGT: case ISD::SETOGT: case ISD::SETUGT:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTLT; rev = true; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETGE: case ISD::SETOGE: case ISD::SETUGE:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTLE; rev = true; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETNE: case ISD::SETONE: case ISD::SETUNE:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTEQ; inv = true; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETO:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTUN; inv = true; break;
|
2007-01-24 18:43:14 +00:00
|
|
|
case ISD::SETUO:
|
2007-04-16 18:10:23 +00:00
|
|
|
Opc = Alpha::CMPTUN; break;
|
2005-11-30 07:19:56 +00:00
|
|
|
};
|
2007-01-24 18:43:14 +00:00
|
|
|
SDOperand tmp1 = N->getOperand(rev?1:0);
|
|
|
|
SDOperand tmp2 = N->getOperand(rev?0:1);
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(tmp1);
|
|
|
|
AddToISelQueue(tmp2);
|
2007-01-24 18:43:14 +00:00
|
|
|
SDNode *cmp = CurDAG->getTargetNode(Opc, MVT::f64, tmp1, tmp2);
|
|
|
|
if (inv)
|
2006-02-09 07:17:49 +00:00
|
|
|
cmp = CurDAG->getTargetNode(Alpha::CMPTEQ, MVT::f64, SDOperand(cmp, 0),
|
2005-11-30 17:11:20 +00:00
|
|
|
CurDAG->getRegister(Alpha::F31, MVT::f64));
|
2007-01-24 18:43:14 +00:00
|
|
|
switch(CC) {
|
|
|
|
case ISD::SETUEQ: case ISD::SETULT: case ISD::SETULE:
|
|
|
|
case ISD::SETUNE: case ISD::SETUGT: case ISD::SETUGE:
|
2007-04-16 18:10:23 +00:00
|
|
|
{
|
|
|
|
SDNode* cmp2 = CurDAG->getTargetNode(Alpha::CMPTUN, MVT::f64,
|
|
|
|
tmp1, tmp2);
|
|
|
|
cmp = CurDAG->getTargetNode(Alpha::ADDT, MVT::f64,
|
|
|
|
SDOperand(cmp2, 0), SDOperand(cmp, 0));
|
|
|
|
break;
|
|
|
|
}
|
2007-01-24 18:43:14 +00:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
2007-01-24 21:09:16 +00:00
|
|
|
SDNode* LD = CurDAG->getTargetNode(Alpha::FTOIT, MVT::i64, SDOperand(cmp, 0));
|
2006-08-26 05:34:46 +00:00
|
|
|
return CurDAG->getTargetNode(Alpha::CMPULT, MVT::i64,
|
|
|
|
CurDAG->getRegister(Alpha::R31, MVT::i64),
|
2007-01-24 21:09:16 +00:00
|
|
|
SDOperand(LD,0));
|
2005-11-30 07:19:56 +00:00
|
|
|
}
|
|
|
|
break;
|
2005-11-30 16:10:29 +00:00
|
|
|
|
2005-12-12 17:43:52 +00:00
|
|
|
case ISD::SELECT:
|
|
|
|
if (MVT::isFloatingPoint(N->getValueType(0)) &&
|
2007-04-16 18:10:23 +00:00
|
|
|
(N->getOperand(0).getOpcode() != ISD::SETCC ||
|
|
|
|
!MVT::isFloatingPoint(N->getOperand(0).getOperand(1).getValueType()))) {
|
2005-12-12 17:43:52 +00:00
|
|
|
//This should be the condition not covered by the Patterns
|
|
|
|
//FIXME: Don't have SelectCode die, but rather return something testable
|
|
|
|
// so that things like this can be caught in fall though code
|
|
|
|
//move int to fp
|
|
|
|
bool isDouble = N->getValueType(0) == MVT::f64;
|
2006-08-26 01:07:58 +00:00
|
|
|
SDOperand cond = N->getOperand(0);
|
|
|
|
SDOperand TV = N->getOperand(1);
|
|
|
|
SDOperand FV = N->getOperand(2);
|
|
|
|
AddToISelQueue(cond);
|
|
|
|
AddToISelQueue(TV);
|
|
|
|
AddToISelQueue(FV);
|
2005-12-12 17:43:52 +00:00
|
|
|
|
2007-01-24 21:09:16 +00:00
|
|
|
SDNode* LD = CurDAG->getTargetNode(Alpha::ITOFT, MVT::f64, cond);
|
2006-08-26 05:34:46 +00:00
|
|
|
return CurDAG->getTargetNode(isDouble?Alpha::FCMOVNET:Alpha::FCMOVNES,
|
2007-01-24 21:09:16 +00:00
|
|
|
MVT::f64, FV, TV, SDOperand(LD,0));
|
2005-12-12 17:43:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2006-02-13 18:52:29 +00:00
|
|
|
case ISD::AND: {
|
2006-05-18 17:29:34 +00:00
|
|
|
ConstantSDNode* SC = NULL;
|
|
|
|
ConstantSDNode* MC = NULL;
|
2006-02-13 18:52:29 +00:00
|
|
|
if (N->getOperand(0).getOpcode() == ISD::SRL &&
|
2007-04-16 18:10:23 +00:00
|
|
|
(MC = dyn_cast<ConstantSDNode>(N->getOperand(1))) &&
|
|
|
|
(SC = dyn_cast<ConstantSDNode>(N->getOperand(0).getOperand(1)))) {
|
|
|
|
uint64_t sval = SC->getValue();
|
|
|
|
uint64_t mval = MC->getValue();
|
|
|
|
// If the result is a zap, let the autogened stuff handle it.
|
|
|
|
if (get_zapImm(N->getOperand(0), mval))
|
|
|
|
break;
|
|
|
|
// given mask X, and shift S, we want to see if there is any zap in the
|
|
|
|
// mask if we play around with the botton S bits
|
|
|
|
uint64_t dontcare = (~0ULL) >> (64 - sval);
|
|
|
|
uint64_t mask = mval << sval;
|
|
|
|
|
|
|
|
if (get_zapImm(mask | dontcare))
|
|
|
|
mask = mask | dontcare;
|
|
|
|
|
|
|
|
if (get_zapImm(mask)) {
|
|
|
|
AddToISelQueue(N->getOperand(0).getOperand(0));
|
|
|
|
SDOperand Z =
|
|
|
|
SDOperand(CurDAG->getTargetNode(Alpha::ZAPNOTi, MVT::i64,
|
|
|
|
N->getOperand(0).getOperand(0),
|
|
|
|
getI64Imm(get_zapImm(mask))), 0);
|
|
|
|
return CurDAG->getTargetNode(Alpha::SRLr, MVT::i64, Z,
|
|
|
|
getI64Imm(sval));
|
2006-02-13 18:52:29 +00:00
|
|
|
}
|
2007-04-16 18:10:23 +00:00
|
|
|
}
|
2006-02-13 18:52:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
}
|
2005-11-30 16:10:29 +00:00
|
|
|
|
2006-08-26 05:34:46 +00:00
|
|
|
return SelectCode(Op);
|
2005-10-20 00:29:02 +00:00
|
|
|
}
|
|
|
|
|
2006-08-26 05:34:46 +00:00
|
|
|
void AlphaDAGToDAGISel::SelectCALL(SDOperand Op) {
|
2005-11-22 04:20:06 +00:00
|
|
|
//TODO: add flag stuff to prevent nondeturministic breakage!
|
|
|
|
|
2005-10-22 22:06:58 +00:00
|
|
|
SDNode *N = Op.Val;
|
2006-08-26 01:07:58 +00:00
|
|
|
SDOperand Chain = N->getOperand(0);
|
2005-12-25 17:36:48 +00:00
|
|
|
SDOperand Addr = N->getOperand(1);
|
2006-04-08 05:38:03 +00:00
|
|
|
SDOperand InFlag(0,0); // Null incoming flag value.
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(Chain);
|
2005-10-22 22:06:58 +00:00
|
|
|
|
|
|
|
std::vector<SDOperand> CallOperands;
|
|
|
|
std::vector<MVT::ValueType> TypeOperands;
|
|
|
|
|
|
|
|
//grab the arguments
|
|
|
|
for(int i = 2, e = N->getNumOperands(); i < e; ++i) {
|
|
|
|
TypeOperands.push_back(N->getOperand(i).getValueType());
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N->getOperand(i));
|
|
|
|
CallOperands.push_back(N->getOperand(i));
|
2005-10-22 22:06:58 +00:00
|
|
|
}
|
2005-10-23 03:43:48 +00:00
|
|
|
int count = N->getNumOperands() - 2;
|
|
|
|
|
2005-10-22 22:06:58 +00:00
|
|
|
static const unsigned args_int[] = {Alpha::R16, Alpha::R17, Alpha::R18,
|
|
|
|
Alpha::R19, Alpha::R20, Alpha::R21};
|
|
|
|
static const unsigned args_float[] = {Alpha::F16, Alpha::F17, Alpha::F18,
|
|
|
|
Alpha::F19, Alpha::F20, Alpha::F21};
|
|
|
|
|
2005-11-30 07:19:56 +00:00
|
|
|
for (int i = 6; i < count; ++i) {
|
|
|
|
unsigned Opc = Alpha::WTF;
|
|
|
|
if (MVT::isInteger(TypeOperands[i])) {
|
|
|
|
Opc = Alpha::STQ;
|
|
|
|
} else if (TypeOperands[i] == MVT::f32) {
|
|
|
|
Opc = Alpha::STS;
|
|
|
|
} else if (TypeOperands[i] == MVT::f64) {
|
|
|
|
Opc = Alpha::STT;
|
|
|
|
} else
|
|
|
|
assert(0 && "Unknown operand");
|
2006-08-27 08:14:06 +00:00
|
|
|
|
|
|
|
SDOperand Ops[] = { CallOperands[i], getI64Imm((i - 6) * 8),
|
|
|
|
CurDAG->getCopyFromReg(Chain, Alpha::R30, MVT::i64),
|
|
|
|
Chain };
|
|
|
|
Chain = SDOperand(CurDAG->getTargetNode(Opc, MVT::Other, Ops, 4), 0);
|
2005-11-30 07:19:56 +00:00
|
|
|
}
|
2005-12-01 01:53:10 +00:00
|
|
|
for (int i = 0; i < std::min(6, count); ++i) {
|
|
|
|
if (MVT::isInteger(TypeOperands[i])) {
|
|
|
|
Chain = CurDAG->getCopyToReg(Chain, args_int[i], CallOperands[i], InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
} else if (TypeOperands[i] == MVT::f32 || TypeOperands[i] == MVT::f64) {
|
|
|
|
Chain = CurDAG->getCopyToReg(Chain, args_float[i], CallOperands[i], InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
} else
|
|
|
|
assert(0 && "Unknown operand");
|
|
|
|
}
|
|
|
|
|
2005-10-22 22:06:58 +00:00
|
|
|
// Finally, once everything is in registers to pass to the call, emit the
|
|
|
|
// call itself.
|
2005-12-25 17:36:48 +00:00
|
|
|
if (Addr.getOpcode() == AlphaISD::GPRelLo) {
|
|
|
|
SDOperand GOT = getGlobalBaseReg();
|
|
|
|
Chain = CurDAG->getCopyToReg(Chain, Alpha::R29, GOT, InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
2006-02-09 07:17:49 +00:00
|
|
|
Chain = SDOperand(CurDAG->getTargetNode(Alpha::BSR, MVT::Other, MVT::Flag,
|
|
|
|
Addr.getOperand(0), Chain, InFlag), 0);
|
2005-12-25 17:36:48 +00:00
|
|
|
} else {
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(Addr);
|
2006-02-09 00:37:58 +00:00
|
|
|
Chain = CurDAG->getCopyToReg(Chain, Alpha::R27, Addr, InFlag);
|
2005-12-25 17:36:48 +00:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-02-09 07:17:49 +00:00
|
|
|
Chain = SDOperand(CurDAG->getTargetNode(Alpha::JSR, MVT::Other, MVT::Flag,
|
|
|
|
Chain, InFlag), 0);
|
2005-12-25 17:36:48 +00:00
|
|
|
}
|
2005-12-01 01:53:10 +00:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
2005-10-22 22:06:58 +00:00
|
|
|
std::vector<SDOperand> CallResults;
|
|
|
|
|
|
|
|
switch (N->getValueType(0)) {
|
|
|
|
default: assert(0 && "Unexpected ret value!");
|
|
|
|
case MVT::Other: break;
|
|
|
|
case MVT::i64:
|
2005-12-01 01:53:10 +00:00
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, Alpha::R0, MVT::i64, InFlag).getValue(1);
|
2005-10-22 22:06:58 +00:00
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
break;
|
2005-11-22 04:20:06 +00:00
|
|
|
case MVT::f32:
|
2005-12-01 01:53:10 +00:00
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, Alpha::F0, MVT::f32, InFlag).getValue(1);
|
2005-11-22 04:20:06 +00:00
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
break;
|
|
|
|
case MVT::f64:
|
2005-12-01 01:53:10 +00:00
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, Alpha::F0, MVT::f64, InFlag).getValue(1);
|
2005-11-22 04:20:06 +00:00
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
break;
|
2005-10-22 22:06:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CallResults.push_back(Chain);
|
|
|
|
for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
|
2006-08-07 22:28:20 +00:00
|
|
|
ReplaceUses(Op.getValue(i), CallResults[i]);
|
2005-10-22 22:06:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-20 00:29:02 +00:00
|
|
|
/// createAlphaISelDag - This pass converts a legalized DAG into a
|
|
|
|
/// Alpha-specific DAG, ready for instruction scheduling.
|
|
|
|
///
|
|
|
|
FunctionPass *llvm::createAlphaISelDag(TargetMachine &TM) {
|
|
|
|
return new AlphaDAGToDAGISel(TM);
|
|
|
|
}
|