llvm-project/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp

768 lines
25 KiB
C++

//===-- PIC16ISelLowering.cpp - PIC16 DAG Lowering Implementation ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that PIC16 uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "pic16-lower"
#include "PIC16ISelLowering.h"
#include "PIC16TargetMachine.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Intrinsics.h"
#include "llvm/CallingConv.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/Debug.h"
#include <queue>
#include <set>
using namespace llvm;
const char *PIC16TargetLowering:: getTargetNodeName(unsigned Opcode) const
{
switch (Opcode) {
case PIC16ISD::Hi : return "PIC16ISD::Hi";
case PIC16ISD::Lo : return "PIC16ISD::Lo";
case PIC16ISD::Package : return "PIC16ISD::Package";
case PIC16ISD::Wrapper : return "PIC16ISD::Wrapper";
case PIC16ISD::SetBank : return "PIC16ISD::SetBank";
case PIC16ISD::SetPage : return "PIC16ISD::SetPage";
case PIC16ISD::Branch : return "PIC16ISD::Branch";
case PIC16ISD::Cmp : return "PIC16ISD::Cmp";
case PIC16ISD::BTFSS : return "PIC16ISD::BTFSS";
case PIC16ISD::BTFSC : return "PIC16ISD::BTFSC";
case PIC16ISD::XORCC : return "PIC16ISD::XORCC";
case PIC16ISD::SUBCC : return "PIC16ISD::SUBCC";
default : return NULL;
}
}
PIC16TargetLowering::
PIC16TargetLowering(PIC16TargetMachine &TM): TargetLowering(TM)
{
// Set up the register classes.
addRegisterClass(MVT::i8, PIC16::CPURegsRegisterClass);
addRegisterClass(MVT::i16, PIC16::PTRRegsRegisterClass);
// Load extented operations for i1 types must be promoted .
setLoadXAction(ISD::EXTLOAD, MVT::i1, Promote);
setLoadXAction(ISD::ZEXTLOAD, MVT::i1, Promote);
setLoadXAction(ISD::SEXTLOAD, MVT::i1, Promote);
setOperationAction(ISD::ADD, MVT::i1, Promote);
setOperationAction(ISD::ADD, MVT::i8, Legal);
setOperationAction(ISD::ADD, MVT::i16, Custom);
setOperationAction(ISD::ADD, MVT::i32, Expand);
setOperationAction(ISD::ADD, MVT::i64, Expand);
setOperationAction(ISD::SUB, MVT::i1, Promote);
setOperationAction(ISD::SUB, MVT::i8, Legal);
setOperationAction(ISD::SUB, MVT::i16, Custom);
setOperationAction(ISD::SUB, MVT::i32, Expand);
setOperationAction(ISD::SUB, MVT::i64, Expand);
setOperationAction(ISD::ADDC, MVT::i1, Promote);
setOperationAction(ISD::ADDC, MVT::i8, Legal);
setOperationAction(ISD::ADDC, MVT::i16, Custom);
setOperationAction(ISD::ADDC, MVT::i32, Expand);
setOperationAction(ISD::ADDC, MVT::i64, Expand);
setOperationAction(ISD::ADDE, MVT::i1, Promote);
setOperationAction(ISD::ADDE, MVT::i8, Legal);
setOperationAction(ISD::ADDE, MVT::i16, Custom);
setOperationAction(ISD::ADDE, MVT::i32, Expand);
setOperationAction(ISD::ADDE, MVT::i64, Expand);
setOperationAction(ISD::SUBC, MVT::i1, Promote);
setOperationAction(ISD::SUBC, MVT::i8, Legal);
setOperationAction(ISD::SUBC, MVT::i16, Custom);
setOperationAction(ISD::SUBC, MVT::i32, Expand);
setOperationAction(ISD::SUBC, MVT::i64, Expand);
setOperationAction(ISD::SUBE, MVT::i1, Promote);
setOperationAction(ISD::SUBE, MVT::i8, Legal);
setOperationAction(ISD::SUBE, MVT::i16, Custom);
setOperationAction(ISD::SUBE, MVT::i32, Expand);
setOperationAction(ISD::SUBE, MVT::i64, Expand);
// PIC16 does not have these NodeTypes below.
setOperationAction(ISD::SETCC, MVT::i1, Expand);
setOperationAction(ISD::SETCC, MVT::i8, Expand);
setOperationAction(ISD::SETCC, MVT::Other, Expand);
setOperationAction(ISD::SELECT_CC, MVT::i1, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i8, Custom);
setOperationAction(ISD::BRCOND, MVT::i1, Expand);
setOperationAction(ISD::BRCOND, MVT::i8, Expand);
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::i1, Custom);
setOperationAction(ISD::BR_CC, MVT::i8, Custom);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
// FIXME: Do we really need to Custom lower the GA ??
setOperationAction(ISD::GlobalAddress, MVT::i8, Custom);
setOperationAction(ISD::RET, MVT::Other, Custom);
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
setOperationAction(ISD::CTTZ, MVT::i32, Expand);
setOperationAction(ISD::CTLZ, MVT::i32, Expand);
setOperationAction(ISD::ROTL, MVT::i32, Expand);
setOperationAction(ISD::ROTR, MVT::i32, Expand);
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
// We don't have line number support yet.
setOperationAction(ISD::LOCATION, MVT::Other, Expand);
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
setOperationAction(ISD::LABEL, MVT::Other, Expand);
// Use the default for now.
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
setOperationAction(ISD::LOAD, MVT::i1, Promote);
setOperationAction(ISD::LOAD, MVT::i8, Legal);
setTargetDAGCombine(ISD::LOAD);
setTargetDAGCombine(ISD::STORE);
setTargetDAGCombine(ISD::ADDE);
setTargetDAGCombine(ISD::ADDC);
setTargetDAGCombine(ISD::ADD);
setTargetDAGCombine(ISD::SUBE);
setTargetDAGCombine(ISD::SUBC);
setTargetDAGCombine(ISD::SUB);
setStackPointerRegisterToSaveRestore(PIC16::STKPTR);
computeRegisterProperties();
}
SDOperand PIC16TargetLowering:: LowerOperation(SDOperand Op, SelectionDAG &DAG)
{
SDVTList VTList16 = DAG.getVTList(MVT::i16, MVT::i16, MVT::Other);
switch (Op.getOpcode()) {
case ISD::STORE:
DOUT << "reduce store\n";
break;
case ISD::FORMAL_ARGUMENTS:
DOUT << "==== lowering formal args\n";
return LowerFORMAL_ARGUMENTS(Op, DAG);
case ISD::GlobalAddress:
DOUT << "==== lowering GA\n";
return LowerGlobalAddress(Op, DAG);
case ISD::RET:
DOUT << "==== lowering ret\n";
return LowerRET(Op, DAG);
case ISD::FrameIndex:
DOUT << "==== lowering frame index\n";
return LowerFrameIndex(Op, DAG);
case ISD::ADDE:
DOUT << "==== lowering adde\n";
break;
case ISD::LOAD:
case ISD::ADD:
break;
case ISD::BR_CC:
DOUT << "==== lowering BR_CC\n";
return LowerBR_CC(Op, DAG);
} // end switch.
return SDOperand();
}
//===----------------------------------------------------------------------===//
// Lower helper functions
//===----------------------------------------------------------------------===//
SDOperand PIC16TargetLowering::LowerBR_CC(SDOperand Op, SelectionDAG &DAG)
{
MVT VT = Op.getValueType();
SDOperand Chain = Op.getOperand(0);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
SDOperand LHS = Op.getOperand(2);
SDOperand RHS = Op.getOperand(3);
SDOperand JumpVal = Op.getOperand(4);
SDOperand Result;
unsigned cmpOpcode;
unsigned branchOpcode;
SDOperand branchOperand;
SDOperand StatusReg = DAG.getRegister(PIC16::STATUSREG, MVT::i8);
SDOperand CPUReg = DAG.getRegister(PIC16::WREG, MVT::i8);
switch(CC) {
default:
assert(0 && "This condition code is not handled yet!!");
abort();
case ISD::SETNE:
DOUT << "setne\n";
cmpOpcode = PIC16ISD::XORCC;
branchOpcode = PIC16ISD::BTFSS;
branchOperand = DAG.getConstant(2, MVT::i8);
break;
case ISD::SETEQ:
DOUT << "seteq\n";
cmpOpcode = PIC16ISD::XORCC;
branchOpcode = PIC16ISD::BTFSC;
branchOperand = DAG.getConstant(2, MVT::i8);
break;
case ISD::SETGT:
assert(0 && "Greater Than condition code is not handled yet!!");
abort();
break;
case ISD::SETGE:
DOUT << "setge\n";
cmpOpcode = PIC16ISD::SUBCC;
branchOpcode = PIC16ISD::BTFSS;
branchOperand = DAG.getConstant(1, MVT::i8);
break;
case ISD::SETLT:
DOUT << "setlt\n";
cmpOpcode = PIC16ISD::SUBCC;
branchOpcode = PIC16ISD::BTFSC;
branchOperand = DAG.getConstant(1,MVT::i8);
break;
case ISD::SETLE:
assert(0 && "Less Than Equal condition code is not handled yet!!");
abort();
break;
} // End of Switch
SDVTList VTList = DAG.getVTList(MVT::i8, MVT::Flag);
SDOperand CmpValue = DAG.getNode(cmpOpcode, VTList, LHS, RHS).getValue(1);
Result = DAG.getNode(branchOpcode, VT, Chain, JumpVal, branchOperand,
StatusReg, CmpValue);
return Result;
}
//===----------------------------------------------------------------------===//
// Misc Lower Operation implementation
//===----------------------------------------------------------------------===//
// LowerGlobalAddress - Create a constant pool entry for global value
// and wrap it in a wrapper node.
SDOperand
PIC16TargetLowering::LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG)
{
MVT PtrVT = getPointerTy();
GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op);
GlobalValue *GV = GSDN->getGlobal();
// FIXME: for now only do the ram.
SDOperand CPAddr = DAG.getTargetConstantPool(GV, PtrVT, 2);
SDOperand CPBank = DAG.getNode(PIC16ISD::SetBank, MVT::i8, CPAddr);
CPAddr = DAG.getNode(PIC16ISD::Wrapper, MVT::i8, CPAddr,CPBank);
return CPAddr;
}
SDOperand
PIC16TargetLowering::LowerRET(SDOperand Op, SelectionDAG &DAG)
{
switch(Op.getNumOperands()) {
default:
assert(0 && "Do not know how to return this many arguments!");
abort();
case 1:
return SDOperand(); // ret void is legal
}
}
SDOperand
PIC16TargetLowering::LowerFrameIndex(SDOperand N, SelectionDAG &DAG)
{
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
return DAG.getTargetFrameIndex(FIN->getIndex(), MVT::i32);
}
return N;
}
SDOperand
PIC16TargetLowering::LowerLOAD(SDNode *N,
SelectionDAG &DAG,
DAGCombinerInfo &DCI) const
{
SDOperand Outs[2];
SDOperand TF; //TokenFactor
SDOperand OutChains[2];
SDOperand Chain = N->getOperand(0);
SDOperand Src = N->getOperand(1);
SDOperand retVal;
SDVTList VTList;
// If this load is directly stored, replace the load value with the stored
// value.
// FIXME: Handle store large -> read small portion.
// FIXME: Handle TRUNCSTORE/LOADEXT
LoadSDNode *LD = cast<LoadSDNode>(N);
SDOperand Ptr = LD->getBasePtr();
if (LD->getExtensionType() == ISD::NON_EXTLOAD) {
if (ISD::isNON_TRUNCStore(Chain.Val)) {
StoreSDNode *PrevST = cast<StoreSDNode>(Chain);
if (PrevST->getBasePtr() == Ptr &&
PrevST->getValue().getValueType() == N->getValueType(0))
return DCI.CombineTo(N, Chain.getOperand(1), Chain);
}
}
if (N->getValueType(0) != MVT::i16)
return SDOperand();
SDOperand toWorklist;
Outs[0] = DAG.getLoad(MVT::i8, Chain, Src, NULL, 0);
toWorklist = DAG.getNode(ISD::ADD, MVT::i16, Src,
DAG.getConstant(1, MVT::i16));
Outs[1] = DAG.getLoad(MVT::i8, Chain, toWorklist, NULL, 0);
// FIXME: Add to worklist may not be needed.
// It is meant to merge sequences of add with constant into one.
DCI.AddToWorklist(toWorklist.Val);
// Create the tokenfactors and carry it on to the build_pair node
OutChains[0] = Outs[0].getValue(1);
OutChains[1] = Outs[1].getValue(1);
TF = DAG.getNode(ISD::TokenFactor, MVT::Other, &OutChains[0], 2);
VTList = DAG.getVTList(MVT::i16, MVT::Flag);
retVal = DAG.getNode (PIC16ISD::Package, VTList, &Outs[0], 2);
DCI.CombineTo (N, retVal, TF);
return retVal;
}
SDOperand
PIC16TargetLowering::LowerADDSUB(SDNode *N, SelectionDAG &DAG,
DAGCombinerInfo &DCI) const
{
bool changed = false;
int i;
SDOperand LoOps[3], HiOps[3];
SDOperand OutOps[3]; // [0]:left, [1]:right, [2]:carry
SDOperand InOp[2];
SDOperand retVal;
SDOperand as1,as2;
SDVTList VTList;
unsigned AS = 0, ASE = 0, ASC=0;
InOp[0] = N->getOperand(0);
InOp[1] = N->getOperand(1);
switch (N->getOpcode()) {
case ISD::ADD:
if (InOp[0].getOpcode() == ISD::Constant &&
InOp[1].getOpcode() == ISD::Constant) {
ConstantSDNode *CST0 = dyn_cast<ConstantSDNode>(InOp[0]);
ConstantSDNode *CST1 = dyn_cast<ConstantSDNode>(InOp[1]);
return DAG.getConstant(CST0->getValue() + CST1->getValue(), MVT::i16);
}
break;
case ISD::ADDE:
case ISD::ADDC:
AS = ISD::ADD;
ASE = ISD::ADDE;
ASC = ISD::ADDC;
break;
case ISD::SUB:
if (InOp[0].getOpcode() == ISD::Constant &&
InOp[1].getOpcode() == ISD::Constant) {
ConstantSDNode *CST0 = dyn_cast<ConstantSDNode>(InOp[0]);
ConstantSDNode *CST1 = dyn_cast<ConstantSDNode>(InOp[1]);
return DAG.getConstant(CST0->getValue() - CST1->getValue(), MVT::i16);
}
break;
case ISD::SUBE:
case ISD::SUBC:
AS = ISD::SUB;
ASE = ISD::SUBE;
ASC = ISD::SUBC;
break;
} // end switch.
assert ((N->getValueType(0) == MVT::i16)
&& "expecting an MVT::i16 node for lowering");
assert ((N->getOperand(0).getValueType() == MVT::i16)
&& (N->getOperand(1).getValueType() == MVT::i16)
&& "both inputs to addx/subx:i16 must be i16");
for (i = 0; i < 2; i++) {
if (InOp[i].getOpcode() == ISD::GlobalAddress) {
// We don't want to lower subs/adds with global address yet.
return SDOperand();
}
else if (InOp[i].getOpcode() == ISD::Constant) {
changed = true;
ConstantSDNode *CST = dyn_cast<ConstantSDNode>(InOp[i]);
LoOps[i] = DAG.getConstant(CST->getValue() & 0xFF, MVT::i8);
HiOps[i] = DAG.getConstant(CST->getValue() >> 8, MVT::i8);
}
else if (InOp[i].getOpcode() == PIC16ISD::Package) {
LoOps[i] = InOp[i].getOperand(0);
HiOps[i] = InOp[i].getOperand(1);
}
else if (InOp[i].getOpcode() == ISD::LOAD) {
changed = true;
// LowerLOAD returns a Package node or it may combine and return
// anything else.
SDOperand lowered = LowerLOAD(InOp[i].Val, DAG, DCI);
// So If LowerLOAD returns something other than Package,
// then just call ADD again.
if (lowered.getOpcode() != PIC16ISD::Package)
return LowerADDSUB(N, DAG, DCI);
LoOps[i] = lowered.getOperand(0);
HiOps[i] = lowered.getOperand(1);
}
else if ((InOp[i].getOpcode() == ISD::ADD) ||
(InOp[i].getOpcode() == ISD::ADDE) ||
(InOp[i].getOpcode() == ISD::ADDC) ||
(InOp[i].getOpcode() == ISD::SUB) ||
(InOp[i].getOpcode() == ISD::SUBE) ||
(InOp[i].getOpcode() == ISD::SUBC)) {
changed = true;
// Must call LowerADDSUB recursively here,
// LowerADDSUB returns a Package node.
SDOperand lowered = LowerADDSUB(InOp[i].Val, DAG, DCI);
LoOps[i] = lowered.getOperand(0);
HiOps[i] = lowered.getOperand(1);
}
else if (InOp[i].getOpcode() == ISD::SIGN_EXTEND) {
// FIXME: I am just zero extending. for now.
changed = true;
LoOps[i] = InOp[i].getOperand(0);
HiOps[i] = DAG.getConstant(0, MVT::i8);
}
else {
DAG.setGraphColor(N, "blue");
DAG.viewGraph();
assert (0 && "not implemented yet");
}
} // end for.
assert (changed && "nothing changed while lowering SUBx/ADDx");
VTList = DAG.getVTList(MVT::i8, MVT::Flag);
if (N->getOpcode() == ASE) {
// We must take in the existing carry
// if this node is part of an existing subx/addx sequence.
LoOps[2] = N->getOperand(2).getValue(1);
as1 = DAG.getNode (ASE, VTList, LoOps, 3);
}
else {
as1 = DAG.getNode (ASC, VTList, LoOps, 2);
}
HiOps[2] = as1.getValue(1);
as2 = DAG.getNode (ASE, VTList, HiOps, 3);
// We must build a pair that also provides the carry from sube/adde.
OutOps[0] = as1;
OutOps[1] = as2;
OutOps[2] = as2.getValue(1);
// Breaking an original i16, so lets make the Package also an i16.
if (N->getOpcode() == ASE) {
VTList = DAG.getVTList(MVT::i16, MVT::Flag);
retVal = DAG.getNode (PIC16ISD::Package, VTList, OutOps, 3);
DCI.CombineTo (N, retVal, OutOps[2]);
}
else if (N->getOpcode() == ASC) {
VTList = DAG.getVTList(MVT::i16, MVT::Flag);
retVal = DAG.getNode (PIC16ISD::Package, VTList, OutOps, 2);
DCI.CombineTo (N, retVal, OutOps[2]);
}
else if (N->getOpcode() == AS) {
VTList = DAG.getVTList(MVT::i16);
retVal = DAG.getNode (PIC16ISD::Package, VTList, OutOps, 2);
DCI.CombineTo (N, retVal);
}
return retVal;
}
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//===----------------------------------------------------------------------===//
#include "PIC16GenCallingConv.inc"
//===----------------------------------------------------------------------===//
// CALL Calling Convention Implementation
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// FORMAL_ARGUMENTS Calling Convention Implementation
//===----------------------------------------------------------------------===//
SDOperand PIC16TargetLowering::
LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG)
{
SmallVector<SDOperand, 8> ArgValues;
SDOperand Root = Op.getOperand(0);
// Return the new list of results.
// FIXME: Just copy right now.
ArgValues.push_back(Root);
return DAG.getNode(ISD::MERGE_VALUES, Op.Val->getVTList(), &ArgValues[0],
ArgValues.size()).getValue(Op.ResNo);
}
//===----------------------------------------------------------------------===//
// Return Value Calling Convention Implementation
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// PIC16 Inline Assembly Support
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target Optimization Hooks
//===----------------------------------------------------------------------===//
SDOperand PIC16TargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const
{
int i;
ConstantSDNode *CST;
SelectionDAG &DAG = DCI.DAG;
switch (N->getOpcode()) {
default:
break;
case PIC16ISD::Package:
DOUT << "==== combining PIC16ISD::Package\n";
return SDOperand();
case ISD::ADD:
case ISD::SUB:
if ((N->getOperand(0).getOpcode() == ISD::GlobalAddress) ||
(N->getOperand(0).getOpcode() == ISD::FrameIndex)) {
// Do not touch pointer adds.
return SDOperand ();
}
break;
case ISD::ADDE :
case ISD::ADDC :
case ISD::SUBE :
case ISD::SUBC :
if (N->getValueType(0) == MVT::i16) {
SDOperand retVal = LowerADDSUB(N, DAG,DCI);
// LowerADDSUB has already combined the result,
// so we just return nothing to avoid assertion failure from llvm
// if N has been deleted already.
return SDOperand();
}
else if (N->getValueType(0) == MVT::i8) {
// Sanity check ....
for (int i=0; i<2; i++) {
if (N->getOperand (i).getOpcode() == PIC16ISD::Package) {
assert (0 &&
"don't want to have PIC16ISD::Package as intput to add:i8");
}
}
}
break;
// FIXME: split this large chunk of code.
case ISD::STORE :
{
SDOperand Chain = N->getOperand(0);
SDOperand Src = N->getOperand(1);
SDOperand Dest = N->getOperand(2);
unsigned int DstOff = 0;
int NUM_STORES = 0;
SDOperand Stores[6];
// if source operand is expected to be extended to
// some higher type then - remove this extension
// SDNode and do the extension manually
if ((Src.getOpcode() == ISD::ANY_EXTEND) ||
(Src.getOpcode() == ISD::SIGN_EXTEND) ||
(Src.getOpcode() == ISD::ZERO_EXTEND)) {
Src = Src.Val->getOperand(0);
Stores[0] = DAG.getStore(Chain, Src, Dest, NULL,0);
return Stores[0];
}
switch(Src.getValueType().getSimpleVT()) {
default:
assert(false && "Invalid value type!");
case MVT::i8:
break;
case MVT::i16:
NUM_STORES = 2;
break;
case MVT::i32:
NUM_STORES = 4;
break;
case MVT::i64:
NUM_STORES = 8;
break;
}
if (isa<GlobalAddressSDNode>(Dest) && isa<LoadSDNode>(Src) &&
(Src.getValueType() != MVT::i8)) {
//create direct addressing a = b
Chain = Src.getOperand(0);
for (i=0; i<NUM_STORES; i++) {
SDOperand ADN = DAG.getNode(ISD::ADD, MVT::i16, Src.getOperand(1),
DAG.getConstant(DstOff, MVT::i16));
SDOperand LDN = DAG.getLoad(MVT::i8, Chain, ADN, NULL, 0);
SDOperand DSTADDR = DAG.getNode(ISD::ADD, MVT::i16, Dest,
DAG.getConstant(DstOff, MVT::i16));
Stores[i] = DAG.getStore(Chain, LDN, DSTADDR, NULL, 0);
Chain = Stores[i];
DstOff += 1;
}
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, &Stores[0], i);
return Chain;
}
else if (isa<GlobalAddressSDNode>(Dest) && isa<ConstantSDNode>(Src)
&& (Src.getValueType() != MVT::i8)) {
//create direct addressing a = CONST
CST = dyn_cast<ConstantSDNode>(Src);
for (i = 0; i < NUM_STORES; i++) {
SDOperand CNST = DAG.getConstant(CST->getValue() >> i*8, MVT::i8);
SDOperand ADN = DAG.getNode(ISD::ADD, MVT::i16, Dest,
DAG.getConstant(DstOff, MVT::i16));
Stores[i] = DAG.getStore(Chain, CNST, ADN, NULL, 0);
Chain = Stores[i];
DstOff += 1;
}
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, &Stores[0], i);
return Chain;
}
else if (isa<LoadSDNode>(Dest) && isa<ConstantSDNode>(Src)
&& (Src.getValueType() != MVT::i8)) {
// Create indirect addressing.
CST = dyn_cast<ConstantSDNode>(Src);
Chain = Dest.getOperand(0);
SDOperand Load;
Load = DAG.getLoad(MVT::i16, Chain,Dest.getOperand(1), NULL, 0);
Chain = Load.getValue(1);
for (i=0; i<NUM_STORES; i++) {
SDOperand CNST = DAG.getConstant(CST->getValue() >> i*8, MVT::i8);
Stores[i] = DAG.getStore(Chain, CNST, Load, NULL, 0);
Chain = Stores[i];
DstOff += 1;
}
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, &Stores[0], i);
return Chain;
}
else if (isa<LoadSDNode>(Dest) && isa<GlobalAddressSDNode>(Src)) {
// GlobalAddressSDNode *GAD = dyn_cast<GlobalAddressSDNode>(Src);
return SDOperand();
}
else if (Src.getOpcode() == PIC16ISD::Package) {
StoreSDNode *st = dyn_cast<StoreSDNode>(N);
SDOperand toWorkList, retVal;
Chain = N->getOperand(0);
if (st->isTruncatingStore()) {
retVal = DAG.getStore(Chain, Src.getOperand(0), Dest, NULL, 0);
}
else {
toWorkList = DAG.getNode(ISD::ADD, MVT::i16, Dest,
DAG.getConstant(1, MVT::i16));
Stores[1] = DAG.getStore(Chain, Src.getOperand(0), Dest, NULL, 0);
Stores[0] = DAG.getStore(Chain, Src.getOperand(1), toWorkList, NULL,
0);
// We want to merge sequence of add with constant to one add and a
// constant, so add the ADD node to worklist to have llvm do that
// automatically.
DCI.AddToWorklist(toWorkList.Val);
// We don't need the Package so add to worklist so llvm deletes it
DCI.AddToWorklist(Src.Val);
retVal = DAG.getNode(ISD::TokenFactor, MVT::Other, &Stores[0], 2);
}
return retVal;
}
else if (Src.getOpcode() == ISD::TRUNCATE) {
}
else {
}
} // end ISD::STORE.
break;
case ISD::LOAD :
{
SDOperand Ptr = N->getOperand(1);
if (Ptr.getOpcode() == PIC16ISD::Package) {
assert (0 && "not implemented yet");
}
}
break;
} // end switch.
return SDOperand();
}
//===----------------------------------------------------------------------===//
// Utility functions
//===----------------------------------------------------------------------===//
const SDOperand *PIC16TargetLowering::
findLoadi8(const SDOperand &Src, SelectionDAG &DAG) const
{
unsigned int i;
if ((Src.getOpcode() == ISD::LOAD) && (Src.getValueType() == MVT::i8))
return &Src;
for (i=0; i<Src.getNumOperands(); i++) {
const SDOperand *retVal = findLoadi8(Src.getOperand(i),DAG);
if (retVal) return retVal;
}
return NULL;
}