llvm-6502/lib/Target/PIC16/PIC16ISelLowering.cpp
Sanjiv Gupta 0e68771536 Adding files for Microchip's PIC16 target.
A brief description about PIC16:
===============================
PIC16 is an 8-bit microcontroller with only one 8-bit register which is the 
accumulator. All arithmetic/load/store operations are 8-bit only.
The architecture has two address spaces: program and data. The program memory 
is divided into 2K pages and the data memory is divided into banks of 128 byte, with only 80 usable bytes, resulting in an non-contiguous data memory. 

It supports direct data memory access (by specifying the address as part of the instruction) and indirect data and program memory access (in an unorthodox fashion which utilize a 16 bit pointer register). 

Two classes of registers exist: (8-bit class which is only one
accumulator) (16-bit class, which contains one or more 16 bit
pointer(s))



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51027 91177308-0d34-0410-b5e6-96231b3b80d8
2008-05-13 09:02:57 +00:00

802 lines
27 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)
{
// PIC16 does not have i1 type, so use i8 for
// setcc operations results (slt, sgt, ...).
// setSetCCResultType(MVT::i8);
// setSetCCResultContents(ZeroOrOneSetCCResult);
// Set up the register classes
addRegisterClass(MVT::i8, PIC16::CPURegsRegisterClass);
addRegisterClass(MVT::i16, PIC16::PTRRegsRegisterClass);
// Custom
// 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);
// Store operations for i1 types must be promoted
// setStoreXAction(MVT::i1, Promote);
// setStoreXAction(MVT::i8, Legal);
// setStoreXAction(MVT::i16, Custom);
// setStoreXAction(MVT::i32, Expand);
// setOperationAction(ISD::BUILD_PAIR, MVT::i32, Expand);
// setOperationAction(ISD::BUILD_PAIR, MVT::i16, Expand);
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);
// Do we really need to Custom lower the GA ??
// setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
setOperationAction(ISD::GlobalAddress, MVT::i8, Custom);
setOperationAction(ISD::RET, MVT::Other, Custom);
// PIC16 not supported intrinsics.
// setOperationAction(ISD::MEMMOVE, MVT::Other, Expand);
// setOperationAction(ISD::MEMSET, MVT::Other, Expand);
// setOperationAction(ISD::MEMCPY, MVT::Other, Expand);
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);
// setOperationAction(ISD::LOAD, MVT::i16, Expand);
// setOperationAction(ISD::LOAD, MVT::i32, Expand);
setTargetDAGCombine(ISD::LOAD);
setTargetDAGCombine(ISD::STORE);
setTargetDAGCombine(ISD::ADDE);
setTargetDAGCombine(ISD::ADDC);
setTargetDAGCombine(ISD::ADD);
setTargetDAGCombine(ISD::SUBE);
setTargetDAGCombine(ISD::SUBC);
setTargetDAGCombine(ISD::SUB);
// We must find a way to get rid of Package nodes in the map
// setTargetDAGCombine(PIC16ISD::Package);
// getValueTypeActions().setTypeAction((MVT::ValueType)MVT::i16, Expand);
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:
cout << "reduce store\n";
break;
case ISD::FORMAL_ARGUMENTS:
cout<<"==== lowering formal args\n";
return LowerFORMAL_ARGUMENTS(Op, DAG);
case ISD::GlobalAddress:
cout<<"==== lowering GA\n";
return LowerGlobalAddress(Op, DAG);
case ISD::RET:
cout<<"==== lowering ret\n";
return LowerRET(Op, DAG);
case ISD::FrameIndex:
cout<<"==== lowering frame index\n";
return LowerFrameIndex(Op, DAG);
case ISD::ADDE:
cout <<"==== lowering adde\n";
break;
case ISD::LOAD:
case ISD::ADD:
break;
case ISD::BR_CC:
cout << "==== lowering BR_CC\n";
return LowerBR_CC(Op, DAG);
} //end swithch
return SDOperand();
}
//===----------------------------------------------------------------------===//
// Lower helper functions
//===----------------------------------------------------------------------===//
SDOperand
PIC16TargetLowering::LowerBR_CC(SDOperand Op, SelectionDAG &DAG)
{
MVT::ValueType 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:
{
cout << "setne\n";
cmpOpcode = PIC16ISD::XORCC;
branchOpcode = PIC16ISD::BTFSS;
branchOperand = DAG.getConstant(2,MVT::i8);
break;
}
case ISD::SETEQ:
{
cout << "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();
}
case ISD::SETGE:
{
cout << "setge\n";
cmpOpcode = PIC16ISD::SUBCC;
branchOpcode = PIC16ISD::BTFSS;
branchOperand = DAG.getConstant(1, MVT::i8);
break;
}
case ISD::SETLT:
{
cout << "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();
}
} // End of Switch
SDVTList VTList = DAG.getVTList(MVT::i8, MVT::Flag);
SDOperand CmpValue = DAG.getNode(cmpOpcode, VTList, LHS, RHS).getValue(1);
// SDOperand CCOper = DAG.getConstant(CC,MVT::i8);
// Result = DAG.getNode(branchOpcode,VT, Chain, JumpVal, CCOper, StatusReg,
// CmpValue);
Result = DAG.getNode(branchOpcode, VT, Chain, JumpVal, branchOperand,
StatusReg, CmpValue);
return Result;
// return SDOperand();
}
//===----------------------------------------------------------------------===//
// Misc Lower Operation implementation
//===----------------------------------------------------------------------===//
// Create a constant pool entry for global value and wrap it in a wrapper node.
SDOperand
PIC16TargetLowering::LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG)
{
MVT::ValueType PtrVT = getPointerTy();
GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op);
GlobalValue *GV = GSDN->getGlobal();
//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.
// TODO: Handle store large -> read small portion.
// TODO: 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);
// 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,ASE,ASC;
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);
}
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);
}
case ISD::SUBE:
case ISD::SUBC:
AS = ISD::SUB;
ASE = ISD::SUBE;
ASC = ISD::SUBC;
break;
}
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 (at least not 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
//
// The lower operations present on calling convention works on this order:
// LowerCALL (virt regs --> phys regs, virt regs --> stack)
// LowerFORMAL_ARGUMENTS (phys --> virt regs, stack --> virt regs)
// LowerRET (virt regs --> phys regs)
// LowerCALL (phys regs --> virt regs)
//
//===----------------------------------------------------------------------===//
#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.
// 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 :
cout <<"==== 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 ();
}
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;
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;
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())
{
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 {
// DAG.setGraphColor(N, "blue");
// DAG.viewGraph();
// assert (0 && "input to store not implemented yet");
}
} //end ISD::STORE
break;
case ISD::LOAD :
{
SDOperand Ptr = N->getOperand(1);
if (Ptr.getOpcode() == PIC16ISD::Package) {
// DAG.setGraphColor(N, "blue");
// DAG.viewGraph();
// Here we must make so that:
// Ptr.getOperand(0) --> fsrl
// Ptr.getOperand(1) --> fsrh
assert (0 && "not implemented yet");
}
//return SDOperand();
//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;
}