mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-30 02:32:08 +00:00
d950941e13
Generate code for the Blackfin family of DSPs from Analog Devices: http://www.analog.com/en/embedded-processing-dsp/blackfin/processors/index.html We aim to be compatible with the exsisting GNU toolchain found at: http://blackfin.uclinux.org/gf/project/toolchain The back-end is experimental. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@77897 91177308-0d34-0410-b5e6-96231b3b80d8
192 lines
7.0 KiB
C++
192 lines
7.0 KiB
C++
//===- BlackfinISelDAGToDAG.cpp - A dag to dag inst selector for Blackfin -===//
|
|
//
|
|
// 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 Blackfin target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Blackfin.h"
|
|
#include "BlackfinISelLowering.h"
|
|
#include "BlackfinTargetMachine.h"
|
|
#include "BlackfinRegisterInfo.h"
|
|
#include "llvm/Intrinsics.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Selector Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// BlackfinDAGToDAGISel - Blackfin specific code to select blackfin machine
|
|
/// instructions for SelectionDAG operations.
|
|
namespace {
|
|
class BlackfinDAGToDAGISel : public SelectionDAGISel {
|
|
/// Subtarget - Keep a pointer to the Blackfin Subtarget around so that we
|
|
/// can make the right decision when generating code for different targets.
|
|
//const BlackfinSubtarget &Subtarget;
|
|
public:
|
|
BlackfinDAGToDAGISel(BlackfinTargetMachine &TM, CodeGenOpt::Level OptLevel)
|
|
: SelectionDAGISel(TM, OptLevel) {}
|
|
|
|
virtual void InstructionSelect();
|
|
|
|
virtual const char *getPassName() const {
|
|
return "Blackfin DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
// Include the pieces autogenerated from the target description.
|
|
#include "BlackfinGenDAGISel.inc"
|
|
|
|
private:
|
|
SDNode *Select(SDValue Op);
|
|
bool SelectADDRspii(SDValue Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Offset);
|
|
|
|
// Walk the DAG after instruction selection, fixing register class issues.
|
|
void FixRegisterClasses(SelectionDAG &DAG);
|
|
|
|
const BlackfinInstrInfo &getInstrInfo() {
|
|
return *static_cast<const BlackfinTargetMachine&>(TM).getInstrInfo();
|
|
}
|
|
const BlackfinRegisterInfo *getRegisterInfo() {
|
|
return static_cast<const BlackfinTargetMachine&>(TM).getRegisterInfo();
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
FunctionPass *llvm::createBlackfinISelDag(BlackfinTargetMachine &TM,
|
|
CodeGenOpt::Level OptLevel) {
|
|
return new BlackfinDAGToDAGISel(TM, OptLevel);
|
|
}
|
|
|
|
/// InstructionSelect - This callback is invoked by
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
|
void BlackfinDAGToDAGISel::InstructionSelect() {
|
|
// Select target instructions for the DAG.
|
|
SelectRoot(*CurDAG);
|
|
DOUT << "Selected selection DAG before regclass fixup:\n";
|
|
DEBUG(CurDAG->dump());
|
|
FixRegisterClasses(*CurDAG);
|
|
}
|
|
|
|
SDNode *BlackfinDAGToDAGISel::Select(SDValue Op) {
|
|
SDNode *N = Op.getNode();
|
|
DebugLoc dl = N->getDebugLoc();
|
|
if (N->isMachineOpcode())
|
|
return NULL; // Already selected.
|
|
|
|
switch (N->getOpcode()) {
|
|
default: break;
|
|
case ISD::FrameIndex: {
|
|
// Selects to ADDpp FI, 0 which in turn will become ADDimm7 SP, imm or ADDpp
|
|
// SP, Px
|
|
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
|
SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
|
|
return CurDAG->SelectNodeTo(N, BF::ADDpp, MVT::i32, TFI,
|
|
CurDAG->getTargetConstant(0, MVT::i32));
|
|
}
|
|
}
|
|
|
|
return SelectCode(Op);
|
|
}
|
|
|
|
bool BlackfinDAGToDAGISel::SelectADDRspii(SDValue Op,
|
|
SDValue Addr,
|
|
SDValue &Base,
|
|
SDValue &Offset) {
|
|
FrameIndexSDNode *FIN = 0;
|
|
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
ConstantSDNode *CN = 0;
|
|
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
|
|
(CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
|
|
(CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
|
|
// Constant positive word offset from frame index
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool isCC(const TargetRegisterClass *RC) {
|
|
return RC == &BF::AnyCCRegClass || BF::AnyCCRegClass.hasSubClass(RC);
|
|
}
|
|
|
|
static inline bool isDCC(const TargetRegisterClass *RC) {
|
|
return RC == &BF::DRegClass || BF::DRegClass.hasSubClass(RC) || isCC(RC);
|
|
}
|
|
|
|
static void UpdateNodeOperand(SelectionDAG &DAG,
|
|
SDNode *N,
|
|
unsigned Num,
|
|
SDValue Val) {
|
|
SmallVector<SDValue, 8> ops(N->op_begin(), N->op_end());
|
|
ops[Num] = Val;
|
|
SDValue New = DAG.UpdateNodeOperands(SDValue(N, 0), ops.data(), ops.size());
|
|
DAG.ReplaceAllUsesWith(N, New.getNode());
|
|
}
|
|
|
|
// After instruction selection, insert COPY_TO_REGCLASS nodes to help in
|
|
// choosing the proper register classes.
|
|
void BlackfinDAGToDAGISel::FixRegisterClasses(SelectionDAG &DAG) {
|
|
const BlackfinInstrInfo &TII = getInstrInfo();
|
|
const BlackfinRegisterInfo *TRI = getRegisterInfo();
|
|
DAG.AssignTopologicalOrder();
|
|
HandleSDNode Dummy(DAG.getRoot());
|
|
|
|
for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin();
|
|
NI != DAG.allnodes_end(); ++NI) {
|
|
if (NI->use_empty() || !NI->isMachineOpcode())
|
|
continue;
|
|
const TargetInstrDesc &DefTID = TII.get(NI->getMachineOpcode());
|
|
for (SDNode::use_iterator UI = NI->use_begin(); !UI.atEnd(); ++UI) {
|
|
if (!UI->isMachineOpcode())
|
|
continue;
|
|
|
|
if (UI.getUse().getResNo() >= DefTID.getNumDefs())
|
|
continue;
|
|
const TargetRegisterClass *DefRC =
|
|
DefTID.OpInfo[UI.getUse().getResNo()].getRegClass(TRI);
|
|
|
|
const TargetInstrDesc &UseTID = TII.get(UI->getMachineOpcode());
|
|
if (UseTID.getNumDefs()+UI.getOperandNo() >= UseTID.getNumOperands())
|
|
continue;
|
|
const TargetRegisterClass *UseRC =
|
|
UseTID.OpInfo[UseTID.getNumDefs()+UI.getOperandNo()].getRegClass(TRI);
|
|
if (!DefRC || !UseRC)
|
|
continue;
|
|
// We cannot copy CC <-> !(CC/D)
|
|
if ((isCC(DefRC) && !isDCC(UseRC)) || (isCC(UseRC) && !isDCC(DefRC))) {
|
|
SDNode *Copy =
|
|
DAG.getTargetNode(TargetInstrInfo::COPY_TO_REGCLASS,
|
|
NI->getDebugLoc(),
|
|
MVT::i32,
|
|
UI.getUse().get(),
|
|
DAG.getTargetConstant(BF::DRegClassID, MVT::i32));
|
|
UpdateNodeOperand(DAG, *UI, UI.getOperandNo(), SDValue(Copy, 0));
|
|
}
|
|
}
|
|
}
|
|
DAG.setRoot(Dummy.getValue());
|
|
}
|
|
|