diff options
Diffstat (limited to 'contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp | 1986 |
1 files changed, 1986 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp b/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp new file mode 100644 index 0000000..f479f46 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -0,0 +1,1986 @@ +// +// 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 "PIC16ABINames.h" +#include "PIC16ISelLowering.h" +#include "PIC16TargetObjectFile.h" +#include "PIC16TargetMachine.h" +#include "PIC16MachineFunctionInfo.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalValue.h" +#include "llvm/Function.h" +#include "llvm/CallingConv.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/Support/ErrorHandling.h" + + +using namespace llvm; + +static const char *getIntrinsicName(unsigned opcode) { + std::string Basename; + switch(opcode) { + default: llvm_unreachable("do not know intrinsic name"); + // Arithmetic Right shift for integer types. + case PIC16ISD::SRA_I8: Basename = "sra.i8"; break; + case RTLIB::SRA_I16: Basename = "sra.i16"; break; + case RTLIB::SRA_I32: Basename = "sra.i32"; break; + + // Left shift for integer types. + case PIC16ISD::SLL_I8: Basename = "sll.i8"; break; + case RTLIB::SHL_I16: Basename = "sll.i16"; break; + case RTLIB::SHL_I32: Basename = "sll.i32"; break; + + // Logical Right Shift for integer types. + case PIC16ISD::SRL_I8: Basename = "srl.i8"; break; + case RTLIB::SRL_I16: Basename = "srl.i16"; break; + case RTLIB::SRL_I32: Basename = "srl.i32"; break; + + // Multiply for integer types. + case PIC16ISD::MUL_I8: Basename = "mul.i8"; break; + case RTLIB::MUL_I16: Basename = "mul.i16"; break; + case RTLIB::MUL_I32: Basename = "mul.i32"; break; + + // Signed division for integers. + case RTLIB::SDIV_I16: Basename = "sdiv.i16"; break; + case RTLIB::SDIV_I32: Basename = "sdiv.i32"; break; + + // Unsigned division for integers. + case RTLIB::UDIV_I16: Basename = "udiv.i16"; break; + case RTLIB::UDIV_I32: Basename = "udiv.i32"; break; + + // Signed Modulas for integers. + case RTLIB::SREM_I16: Basename = "srem.i16"; break; + case RTLIB::SREM_I32: Basename = "srem.i32"; break; + + // Unsigned Modulas for integers. + case RTLIB::UREM_I16: Basename = "urem.i16"; break; + case RTLIB::UREM_I32: Basename = "urem.i32"; break; + + ////////////////////// + // LIBCALLS FOR FLOATS + ////////////////////// + + // Float to signed integrals + case RTLIB::FPTOSINT_F32_I8: Basename = "f32_to_si32"; break; + case RTLIB::FPTOSINT_F32_I16: Basename = "f32_to_si32"; break; + case RTLIB::FPTOSINT_F32_I32: Basename = "f32_to_si32"; break; + + // Signed integrals to float. char and int are first sign extended to i32 + // before being converted to float, so an I8_F32 or I16_F32 isn't required. + case RTLIB::SINTTOFP_I32_F32: Basename = "si32_to_f32"; break; + + // Float to Unsigned conversions. + // Signed conversion can be used for unsigned conversion as well. + // In signed and unsigned versions only the interpretation of the + // MSB is different. Bit representation remains the same. + case RTLIB::FPTOUINT_F32_I8: Basename = "f32_to_si32"; break; + case RTLIB::FPTOUINT_F32_I16: Basename = "f32_to_si32"; break; + case RTLIB::FPTOUINT_F32_I32: Basename = "f32_to_si32"; break; + + // Unsigned to Float conversions. char and int are first zero extended + // before being converted to float. + case RTLIB::UINTTOFP_I32_F32: Basename = "ui32_to_f32"; break; + + // Floating point add, sub, mul, div. + case RTLIB::ADD_F32: Basename = "add.f32"; break; + case RTLIB::SUB_F32: Basename = "sub.f32"; break; + case RTLIB::MUL_F32: Basename = "mul.f32"; break; + case RTLIB::DIV_F32: Basename = "div.f32"; break; + + // Floating point comparison + case RTLIB::O_F32: Basename = "unordered.f32"; break; + case RTLIB::UO_F32: Basename = "unordered.f32"; break; + case RTLIB::OLE_F32: Basename = "le.f32"; break; + case RTLIB::OGE_F32: Basename = "ge.f32"; break; + case RTLIB::OLT_F32: Basename = "lt.f32"; break; + case RTLIB::OGT_F32: Basename = "gt.f32"; break; + case RTLIB::OEQ_F32: Basename = "eq.f32"; break; + case RTLIB::UNE_F32: Basename = "neq.f32"; break; + } + + std::string prefix = PAN::getTagName(PAN::PREFIX_SYMBOL); + std::string tagname = PAN::getTagName(PAN::LIBCALL); + std::string Fullname = prefix + tagname + Basename; + + // The name has to live through program life. + return ESNames::createESName(Fullname); +} + +// getStdLibCallName - Get the name for the standard library function. +static const char *getStdLibCallName(unsigned opcode) { + std::string BaseName; + switch(opcode) { + case RTLIB::COS_F32: BaseName = "cos"; + break; + case RTLIB::SIN_F32: BaseName = "sin"; + break; + case RTLIB::MEMCPY: BaseName = "memcpy"; + break; + case RTLIB::MEMSET: BaseName = "memset"; + break; + case RTLIB::MEMMOVE: BaseName = "memmove"; + break; + default: llvm_unreachable("do not know std lib call name"); + } + std::string prefix = PAN::getTagName(PAN::PREFIX_SYMBOL); + std::string LibCallName = prefix + BaseName; + + // The name has to live through program life. + return ESNames::createESName(LibCallName); +} + +// PIC16TargetLowering Constructor. +PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM) + : TargetLowering(TM, new PIC16TargetObjectFile()) { + + Subtarget = &TM.getSubtarget<PIC16Subtarget>(); + + addRegisterClass(MVT::i8, PIC16::GPRRegisterClass); + + setShiftAmountType(MVT::i8); + + // Std lib call names + setLibcallName(RTLIB::COS_F32, getStdLibCallName(RTLIB::COS_F32)); + setLibcallName(RTLIB::SIN_F32, getStdLibCallName(RTLIB::SIN_F32)); + setLibcallName(RTLIB::MEMCPY, getStdLibCallName(RTLIB::MEMCPY)); + setLibcallName(RTLIB::MEMSET, getStdLibCallName(RTLIB::MEMSET)); + setLibcallName(RTLIB::MEMMOVE, getStdLibCallName(RTLIB::MEMMOVE)); + + // SRA library call names + setPIC16LibcallName(PIC16ISD::SRA_I8, getIntrinsicName(PIC16ISD::SRA_I8)); + setLibcallName(RTLIB::SRA_I16, getIntrinsicName(RTLIB::SRA_I16)); + setLibcallName(RTLIB::SRA_I32, getIntrinsicName(RTLIB::SRA_I32)); + + // SHL library call names + setPIC16LibcallName(PIC16ISD::SLL_I8, getIntrinsicName(PIC16ISD::SLL_I8)); + setLibcallName(RTLIB::SHL_I16, getIntrinsicName(RTLIB::SHL_I16)); + setLibcallName(RTLIB::SHL_I32, getIntrinsicName(RTLIB::SHL_I32)); + + // SRL library call names + setPIC16LibcallName(PIC16ISD::SRL_I8, getIntrinsicName(PIC16ISD::SRL_I8)); + setLibcallName(RTLIB::SRL_I16, getIntrinsicName(RTLIB::SRL_I16)); + setLibcallName(RTLIB::SRL_I32, getIntrinsicName(RTLIB::SRL_I32)); + + // MUL Library call names + setPIC16LibcallName(PIC16ISD::MUL_I8, getIntrinsicName(PIC16ISD::MUL_I8)); + setLibcallName(RTLIB::MUL_I16, getIntrinsicName(RTLIB::MUL_I16)); + setLibcallName(RTLIB::MUL_I32, getIntrinsicName(RTLIB::MUL_I32)); + + // Signed division lib call names + setLibcallName(RTLIB::SDIV_I16, getIntrinsicName(RTLIB::SDIV_I16)); + setLibcallName(RTLIB::SDIV_I32, getIntrinsicName(RTLIB::SDIV_I32)); + + // Unsigned division lib call names + setLibcallName(RTLIB::UDIV_I16, getIntrinsicName(RTLIB::UDIV_I16)); + setLibcallName(RTLIB::UDIV_I32, getIntrinsicName(RTLIB::UDIV_I32)); + + // Signed remainder lib call names + setLibcallName(RTLIB::SREM_I16, getIntrinsicName(RTLIB::SREM_I16)); + setLibcallName(RTLIB::SREM_I32, getIntrinsicName(RTLIB::SREM_I32)); + + // Unsigned remainder lib call names + setLibcallName(RTLIB::UREM_I16, getIntrinsicName(RTLIB::UREM_I16)); + setLibcallName(RTLIB::UREM_I32, getIntrinsicName(RTLIB::UREM_I32)); + + // Floating point to signed int conversions. + setLibcallName(RTLIB::FPTOSINT_F32_I8, + getIntrinsicName(RTLIB::FPTOSINT_F32_I8)); + setLibcallName(RTLIB::FPTOSINT_F32_I16, + getIntrinsicName(RTLIB::FPTOSINT_F32_I16)); + setLibcallName(RTLIB::FPTOSINT_F32_I32, + getIntrinsicName(RTLIB::FPTOSINT_F32_I32)); + + // Signed int to floats. + setLibcallName(RTLIB::SINTTOFP_I32_F32, + getIntrinsicName(RTLIB::SINTTOFP_I32_F32)); + + // Floating points to unsigned ints. + setLibcallName(RTLIB::FPTOUINT_F32_I8, + getIntrinsicName(RTLIB::FPTOUINT_F32_I8)); + setLibcallName(RTLIB::FPTOUINT_F32_I16, + getIntrinsicName(RTLIB::FPTOUINT_F32_I16)); + setLibcallName(RTLIB::FPTOUINT_F32_I32, + getIntrinsicName(RTLIB::FPTOUINT_F32_I32)); + + // Unsigned int to floats. + setLibcallName(RTLIB::UINTTOFP_I32_F32, + getIntrinsicName(RTLIB::UINTTOFP_I32_F32)); + + // Floating point add, sub, mul ,div. + setLibcallName(RTLIB::ADD_F32, getIntrinsicName(RTLIB::ADD_F32)); + setLibcallName(RTLIB::SUB_F32, getIntrinsicName(RTLIB::SUB_F32)); + setLibcallName(RTLIB::MUL_F32, getIntrinsicName(RTLIB::MUL_F32)); + setLibcallName(RTLIB::DIV_F32, getIntrinsicName(RTLIB::DIV_F32)); + + // Floationg point comparison + setLibcallName(RTLIB::O_F32, getIntrinsicName(RTLIB::O_F32)); + setLibcallName(RTLIB::UO_F32, getIntrinsicName(RTLIB::UO_F32)); + setLibcallName(RTLIB::OLE_F32, getIntrinsicName(RTLIB::OLE_F32)); + setLibcallName(RTLIB::OGE_F32, getIntrinsicName(RTLIB::OGE_F32)); + setLibcallName(RTLIB::OLT_F32, getIntrinsicName(RTLIB::OLT_F32)); + setLibcallName(RTLIB::OGT_F32, getIntrinsicName(RTLIB::OGT_F32)); + setLibcallName(RTLIB::OEQ_F32, getIntrinsicName(RTLIB::OEQ_F32)); + setLibcallName(RTLIB::UNE_F32, getIntrinsicName(RTLIB::UNE_F32)); + + // Return value comparisons of floating point calls. + setCmpLibcallCC(RTLIB::OEQ_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::UNE_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OLT_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OLE_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OGE_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OGT_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::UO_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::O_F32, ISD::SETEQ); + + setOperationAction(ISD::GlobalAddress, MVT::i16, Custom); + setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom); + + setOperationAction(ISD::LOAD, MVT::i8, Legal); + setOperationAction(ISD::LOAD, MVT::i16, Custom); + setOperationAction(ISD::LOAD, MVT::i32, Custom); + + setOperationAction(ISD::STORE, MVT::i8, Legal); + setOperationAction(ISD::STORE, MVT::i16, Custom); + setOperationAction(ISD::STORE, MVT::i32, Custom); + setOperationAction(ISD::STORE, MVT::i64, Custom); + + setOperationAction(ISD::ADDE, MVT::i8, Custom); + setOperationAction(ISD::ADDC, MVT::i8, Custom); + setOperationAction(ISD::SUBE, MVT::i8, Custom); + setOperationAction(ISD::SUBC, MVT::i8, Custom); + setOperationAction(ISD::SUB, MVT::i8, Custom); + setOperationAction(ISD::ADD, MVT::i8, Custom); + setOperationAction(ISD::ADD, MVT::i16, Custom); + + setOperationAction(ISD::OR, MVT::i8, Custom); + setOperationAction(ISD::AND, MVT::i8, Custom); + setOperationAction(ISD::XOR, MVT::i8, Custom); + + setOperationAction(ISD::FrameIndex, MVT::i16, Custom); + + setOperationAction(ISD::MUL, MVT::i8, Custom); + + setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::MULHU, MVT::i8, Expand); + setOperationAction(ISD::MULHS, MVT::i8, Expand); + + setOperationAction(ISD::SRA, MVT::i8, Custom); + setOperationAction(ISD::SHL, MVT::i8, Custom); + setOperationAction(ISD::SRL, MVT::i8, Custom); + + setOperationAction(ISD::ROTL, MVT::i8, Expand); + setOperationAction(ISD::ROTR, MVT::i8, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + // PIC16 does not support shift parts + setOperationAction(ISD::SRA_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i8, Expand); + + + // PIC16 does not have a SETCC, expand it to SELECT_CC. + setOperationAction(ISD::SETCC, MVT::i8, Expand); + setOperationAction(ISD::SELECT, MVT::i8, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BRIND, MVT::Other, Expand); + + setOperationAction(ISD::SELECT_CC, MVT::i8, Custom); + setOperationAction(ISD::BR_CC, MVT::i8, Custom); + + //setOperationAction(ISD::TRUNCATE, MVT::i16, Custom); + setTruncStoreAction(MVT::i16, MVT::i8, Custom); + + // Now deduce the information based on the above mentioned + // actions + computeRegisterProperties(); +} + +// getOutFlag - Extract the flag result if the Op has it. +static SDValue getOutFlag(SDValue &Op) { + // Flag is the last value of the node. + SDValue Flag = Op.getValue(Op.getNode()->getNumValues() - 1); + + assert (Flag.getValueType() == MVT::Flag + && "Node does not have an out Flag"); + + return Flag; +} +// Get the TmpOffset for FrameIndex +unsigned PIC16TargetLowering::GetTmpOffsetForFI(unsigned FI, unsigned size, + MachineFunction &MF) const { + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + std::map<unsigned, unsigned> &FiTmpOffsetMap = FuncInfo->getFiTmpOffsetMap(); + + std::map<unsigned, unsigned>::iterator + MapIt = FiTmpOffsetMap.find(FI); + if (MapIt != FiTmpOffsetMap.end()) + return MapIt->second; + + // This FI (FrameIndex) is not yet mapped, so map it + FiTmpOffsetMap[FI] = FuncInfo->getTmpSize(); + FuncInfo->setTmpSize(FuncInfo->getTmpSize() + size); + return FiTmpOffsetMap[FI]; +} + +void PIC16TargetLowering::ResetTmpOffsetMap(SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + FuncInfo->getFiTmpOffsetMap().clear(); + FuncInfo->setTmpSize(0); +} + +// To extract chain value from the SDValue Nodes +// This function will help to maintain the chain extracting +// code at one place. In case of any change in future it will +// help maintain the code. +static SDValue getChain(SDValue &Op) { + SDValue Chain = Op.getValue(Op.getNode()->getNumValues() - 1); + + // If the last value returned in Flag then the chain is + // second last value returned. + if (Chain.getValueType() == MVT::Flag) + Chain = Op.getValue(Op.getNode()->getNumValues() - 2); + + // All nodes may not produce a chain. Therefore following assert + // verifies that the node is returning a chain only. + assert (Chain.getValueType() == MVT::Other + && "Node does not have a chain"); + + return Chain; +} + +/// PopulateResults - Helper function to LowerOperation. +/// If a node wants to return multiple results after lowering, +/// it stuffs them into an array of SDValue called Results. + +static void PopulateResults(SDValue N, SmallVectorImpl<SDValue>&Results) { + if (N.getOpcode() == ISD::MERGE_VALUES) { + int NumResults = N.getNumOperands(); + for( int i = 0; i < NumResults; i++) + Results.push_back(N.getOperand(i)); + } + else + Results.push_back(N); +} + +MVT::SimpleValueType +PIC16TargetLowering::getSetCCResultType(EVT ValType) const { + return MVT::i8; +} + +MVT::SimpleValueType +PIC16TargetLowering::getCmpLibcallReturnType() const { + return MVT::i8; +} + +/// The type legalizer framework of generating legalizer can generate libcalls +/// only when the operand/result types are illegal. +/// PIC16 needs to generate libcalls even for the legal types (i8) for some ops. +/// For example an arithmetic right shift. These functions are used to lower +/// such operations that generate libcall for legal types. + +void +PIC16TargetLowering::setPIC16LibcallName(PIC16ISD::PIC16Libcall Call, + const char *Name) { + PIC16LibcallNames[Call] = Name; +} + +const char * +PIC16TargetLowering::getPIC16LibcallName(PIC16ISD::PIC16Libcall Call) const { + return PIC16LibcallNames[Call]; +} + +SDValue +PIC16TargetLowering::MakePIC16Libcall(PIC16ISD::PIC16Libcall Call, + EVT RetVT, const SDValue *Ops, + unsigned NumOps, bool isSigned, + SelectionDAG &DAG, DebugLoc dl) const { + + TargetLowering::ArgListTy Args; + Args.reserve(NumOps); + + TargetLowering::ArgListEntry Entry; + for (unsigned i = 0; i != NumOps; ++i) { + Entry.Node = Ops[i]; + Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext()); + Entry.isSExt = isSigned; + Entry.isZExt = !isSigned; + Args.push_back(Entry); + } + + SDValue Callee = DAG.getExternalSymbol(getPIC16LibcallName(Call), MVT::i16); + + const Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); + std::pair<SDValue,SDValue> CallInfo = + LowerCallTo(DAG.getEntryNode(), RetTy, isSigned, !isSigned, false, + false, 0, CallingConv::C, false, + /*isReturnValueUsed=*/true, + Callee, Args, DAG, dl); + + return CallInfo.first; +} + +const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return NULL; + case PIC16ISD::Lo: return "PIC16ISD::Lo"; + case PIC16ISD::Hi: return "PIC16ISD::Hi"; + case PIC16ISD::MTLO: return "PIC16ISD::MTLO"; + case PIC16ISD::MTHI: return "PIC16ISD::MTHI"; + case PIC16ISD::MTPCLATH: return "PIC16ISD::MTPCLATH"; + case PIC16ISD::PIC16Connect: return "PIC16ISD::PIC16Connect"; + case PIC16ISD::Banksel: return "PIC16ISD::Banksel"; + case PIC16ISD::PIC16Load: return "PIC16ISD::PIC16Load"; + case PIC16ISD::PIC16LdArg: return "PIC16ISD::PIC16LdArg"; + case PIC16ISD::PIC16LdWF: return "PIC16ISD::PIC16LdWF"; + case PIC16ISD::PIC16Store: return "PIC16ISD::PIC16Store"; + case PIC16ISD::PIC16StWF: return "PIC16ISD::PIC16StWF"; + case PIC16ISD::BCF: return "PIC16ISD::BCF"; + case PIC16ISD::LSLF: return "PIC16ISD::LSLF"; + case PIC16ISD::LRLF: return "PIC16ISD::LRLF"; + case PIC16ISD::RLF: return "PIC16ISD::RLF"; + case PIC16ISD::RRF: return "PIC16ISD::RRF"; + case PIC16ISD::CALL: return "PIC16ISD::CALL"; + case PIC16ISD::CALLW: return "PIC16ISD::CALLW"; + case PIC16ISD::SUBCC: return "PIC16ISD::SUBCC"; + case PIC16ISD::SELECT_ICC: return "PIC16ISD::SELECT_ICC"; + case PIC16ISD::BRCOND: return "PIC16ISD::BRCOND"; + case PIC16ISD::RET: return "PIC16ISD::RET"; + case PIC16ISD::Dummy: return "PIC16ISD::Dummy"; + } +} + +void PIC16TargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) const { + + switch (N->getOpcode()) { + case ISD::GlobalAddress: + Results.push_back(ExpandGlobalAddress(N, DAG)); + return; + case ISD::ExternalSymbol: + Results.push_back(ExpandExternalSymbol(N, DAG)); + return; + case ISD::STORE: + Results.push_back(ExpandStore(N, DAG)); + return; + case ISD::LOAD: + PopulateResults(ExpandLoad(N, DAG), Results); + return; + case ISD::ADD: + // Results.push_back(ExpandAdd(N, DAG)); + return; + case ISD::FrameIndex: + Results.push_back(ExpandFrameIndex(N, DAG)); + return; + default: + assert (0 && "not implemented"); + return; + } +} + +SDValue PIC16TargetLowering::ExpandFrameIndex(SDNode *N, + SelectionDAG &DAG) const { + + // Currently handling FrameIndex of size MVT::i16 only + // One example of this scenario is when return value is written on + // FrameIndex#0 + + if (N->getValueType(0) != MVT::i16) + return SDValue(); + + // Expand the FrameIndex into ExternalSymbol and a Constant node + // The constant will represent the frame index number + // Get the current function frame + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + const std::string Name = Func->getName(); + + FrameIndexSDNode *FR = dyn_cast<FrameIndexSDNode>(SDValue(N,0)); + // FIXME there isn't really debug info here + DebugLoc dl = FR->getDebugLoc(); + + // Expand FrameIndex like GlobalAddress and ExternalSymbol + // Also use Offset field for lo and hi parts. The default + // offset is zero. + + SDValue ES; + int FrameOffset; + SDValue FI = SDValue(N,0); + LegalizeFrameIndex(FI, DAG, ES, FrameOffset); + SDValue Offset = DAG.getConstant(FrameOffset, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, ES, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, ES, Offset); + return DAG.getNode(ISD::BUILD_PAIR, dl, N->getValueType(0), Lo, Hi); +} + + +SDValue PIC16TargetLowering::ExpandStore(SDNode *N, SelectionDAG &DAG) const { + StoreSDNode *St = cast<StoreSDNode>(N); + SDValue Chain = St->getChain(); + SDValue Src = St->getValue(); + SDValue Ptr = St->getBasePtr(); + EVT ValueType = Src.getValueType(); + unsigned StoreOffset = 0; + DebugLoc dl = N->getDebugLoc(); + + SDValue PtrLo, PtrHi; + LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, StoreOffset, dl); + + if (ValueType == MVT::i8) { + return DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, Src, + PtrLo, PtrHi, + DAG.getConstant (0 + StoreOffset, MVT::i8)); + } + else if (ValueType == MVT::i16) { + // Get the Lo and Hi parts from MERGE_VALUE or BUILD_PAIR. + SDValue SrcLo, SrcHi; + GetExpandedParts(Src, DAG, SrcLo, SrcHi); + SDValue ChainLo = Chain, ChainHi = Chain; + // FIXME: This makes unsafe assumptions. The Chain may be a TokenFactor + // created for an unrelated purpose, in which case it may not have + // exactly two operands. Also, even if it does have two operands, they + // may not be the low and high parts of an aligned load that was split. + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue Store1 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, + ChainLo, + SrcLo, PtrLo, PtrHi, + DAG.getConstant (0 + StoreOffset, MVT::i8)); + + SDValue Store2 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainHi, + SrcHi, PtrLo, PtrHi, + DAG.getConstant (1 + StoreOffset, MVT::i8)); + + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, getChain(Store1), + getChain(Store2)); + } + else if (ValueType == MVT::i32) { + // Get the Lo and Hi parts from MERGE_VALUE or BUILD_PAIR. + SDValue SrcLo, SrcHi; + GetExpandedParts(Src, DAG, SrcLo, SrcHi); + + // Get the expanded parts of each of SrcLo and SrcHi. + SDValue SrcLo1, SrcLo2, SrcHi1, SrcHi2; + GetExpandedParts(SrcLo, DAG, SrcLo1, SrcLo2); + GetExpandedParts(SrcHi, DAG, SrcHi1, SrcHi2); + + SDValue ChainLo = Chain, ChainHi = Chain; + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue ChainLo1 = ChainLo, ChainLo2 = ChainLo, ChainHi1 = ChainHi, + ChainHi2 = ChainHi; + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (ChainLo.getOpcode() == ISD::TokenFactor) { + ChainLo1 = ChainLo.getOperand(0); + ChainLo2 = ChainLo.getOperand(1); + } + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (ChainHi.getOpcode() == ISD::TokenFactor) { + ChainHi1 = ChainHi.getOperand(0); + ChainHi2 = ChainHi.getOperand(1); + } + SDValue Store1 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, + ChainLo1, + SrcLo1, PtrLo, PtrHi, + DAG.getConstant (0 + StoreOffset, MVT::i8)); + + SDValue Store2 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainLo2, + SrcLo2, PtrLo, PtrHi, + DAG.getConstant (1 + StoreOffset, MVT::i8)); + + SDValue Store3 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainHi1, + SrcHi1, PtrLo, PtrHi, + DAG.getConstant (2 + StoreOffset, MVT::i8)); + + SDValue Store4 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainHi2, + SrcHi2, PtrLo, PtrHi, + DAG.getConstant (3 + StoreOffset, MVT::i8)); + + SDValue RetLo = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(Store1), getChain(Store2)); + SDValue RetHi = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(Store3), getChain(Store4)); + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, RetLo, RetHi); + + } else if (ValueType == MVT::i64) { + SDValue SrcLo, SrcHi; + GetExpandedParts(Src, DAG, SrcLo, SrcHi); + SDValue ChainLo = Chain, ChainHi = Chain; + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue Store1 = DAG.getStore(ChainLo, dl, SrcLo, Ptr, NULL, + 0 + StoreOffset, false, false, 0); + + Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, + DAG.getConstant(4, Ptr.getValueType())); + SDValue Store2 = DAG.getStore(ChainHi, dl, SrcHi, Ptr, NULL, + 1 + StoreOffset, false, false, 0); + + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store1, + Store2); + } else { + assert (0 && "value type not supported"); + return SDValue(); + } +} + +SDValue PIC16TargetLowering::ExpandExternalSymbol(SDNode *N, + SelectionDAG &DAG) + const { + ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(SDValue(N, 0)); + // FIXME there isn't really debug info here + DebugLoc dl = ES->getDebugLoc(); + + SDValue TES = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8); + SDValue Offset = DAG.getConstant(0, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, TES, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, TES, Offset); + + return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, Lo, Hi); +} + +// ExpandGlobalAddress - +SDValue PIC16TargetLowering::ExpandGlobalAddress(SDNode *N, + SelectionDAG &DAG) const { + GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(SDValue(N, 0)); + // FIXME there isn't really debug info here + DebugLoc dl = G->getDebugLoc(); + + SDValue TGA = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i8, + G->getOffset()); + + SDValue Offset = DAG.getConstant(0, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, TGA, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, TGA, Offset); + + return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, Lo, Hi); +} + +bool PIC16TargetLowering::isDirectAddress(const SDValue &Op) const { + assert (Op.getNode() != NULL && "Can't operate on NULL SDNode!!"); + + if (Op.getOpcode() == ISD::BUILD_PAIR) { + if (Op.getOperand(0).getOpcode() == PIC16ISD::Lo) + return true; + } + return false; +} + +// Return true if DirectAddress is in ROM_SPACE +bool PIC16TargetLowering::isRomAddress(const SDValue &Op) const { + + // RomAddress is a GlobalAddress in ROM_SPACE_ + // If the Op is not a GlobalAddress return NULL without checking + // anything further. + if (!isDirectAddress(Op)) + return false; + + // Its a GlobalAddress. + // It is BUILD_PAIR((PIC16Lo TGA), (PIC16Hi TGA)) and Op is BUILD_PAIR + SDValue TGA = Op.getOperand(0).getOperand(0); + GlobalAddressSDNode *GSDN = dyn_cast<GlobalAddressSDNode>(TGA); + + if (GSDN->getAddressSpace() == PIC16ISD::ROM_SPACE) + return true; + + // Any other address space return it false + return false; +} + + +// GetExpandedParts - This function is on the similiar lines as +// the GetExpandedInteger in type legalizer is. This returns expanded +// parts of Op in Lo and Hi. + +void PIC16TargetLowering::GetExpandedParts(SDValue Op, SelectionDAG &DAG, + SDValue &Lo, SDValue &Hi) const { + SDNode *N = Op.getNode(); + DebugLoc dl = N->getDebugLoc(); + EVT NewVT = getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + + // Extract the lo component. + Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NewVT, Op, + DAG.getConstant(0, MVT::i8)); + + // extract the hi component + Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NewVT, Op, + DAG.getConstant(1, MVT::i8)); +} + +// Legalize FrameIndex into ExternalSymbol and offset. +void +PIC16TargetLowering::LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG, + SDValue &ES, int &Offset) const { + + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + const std::string Name = Func->getName(); + + FrameIndexSDNode *FR = dyn_cast<FrameIndexSDNode>(Op); + + // FrameIndices are not stack offsets. But they represent the request + // for space on stack. That space requested may be more than one byte. + // Therefore, to calculate the stack offset that a FrameIndex aligns + // with, we need to traverse all the FrameIndices available earlier in + // the list and add their requested size. + unsigned FIndex = FR->getIndex(); + const char *tmpName; + if (FIndex < FuncInfo->getReservedFrameCount()) { + tmpName = ESNames::createESName(PAN::getFrameLabel(Name)); + ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + Offset = 0; + for (unsigned i=0; i<FIndex ; ++i) { + Offset += MFI->getObjectSize(i); + } + } else { + // FrameIndex has been made for some temporary storage + tmpName = ESNames::createESName(PAN::getTempdataLabel(Name)); + ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + Offset = GetTmpOffsetForFI(FIndex, MFI->getObjectSize(FIndex), MF); + } + + return; +} + +// This function legalizes the PIC16 Addresses. If the Pointer is +// -- Direct address variable residing +// --> then a Banksel for that variable will be created. +// -- Rom variable +// --> then it will be treated as an indirect address. +// -- Indirect address +// --> then the address will be loaded into FSR +// -- ADD with constant operand +// --> then constant operand of ADD will be returned as Offset +// and non-constant operand of ADD will be treated as pointer. +// Returns the high and lo part of the address, and the offset(in case of ADD). + +void PIC16TargetLowering::LegalizeAddress(SDValue Ptr, SelectionDAG &DAG, + SDValue &Lo, SDValue &Hi, + unsigned &Offset, DebugLoc dl) const { + + // Offset, by default, should be 0 + Offset = 0; + + // If the pointer is ADD with constant, + // return the constant value as the offset + if (Ptr.getOpcode() == ISD::ADD) { + SDValue OperLeft = Ptr.getOperand(0); + SDValue OperRight = Ptr.getOperand(1); + if ((OperLeft.getOpcode() == ISD::Constant) && + (dyn_cast<ConstantSDNode>(OperLeft)->getZExtValue() < 32 )) { + Offset = dyn_cast<ConstantSDNode>(OperLeft)->getZExtValue(); + Ptr = OperRight; + } else if ((OperRight.getOpcode() == ISD::Constant) && + (dyn_cast<ConstantSDNode>(OperRight)->getZExtValue() < 32 )){ + Offset = dyn_cast<ConstantSDNode>(OperRight)->getZExtValue(); + Ptr = OperLeft; + } + } + + // If the pointer is Type i8 and an external symbol + // then treat it as direct address. + // One example for such case is storing and loading + // from function frame during a call + if (Ptr.getValueType() == MVT::i8) { + switch (Ptr.getOpcode()) { + case ISD::TargetExternalSymbol: + Lo = Ptr; + Hi = DAG.getConstant(1, MVT::i8); + return; + } + } + + // Expansion of FrameIndex has Lo/Hi parts + if (isDirectAddress(Ptr)) { + SDValue TFI = Ptr.getOperand(0).getOperand(0); + int FrameOffset; + if (TFI.getOpcode() == ISD::TargetFrameIndex) { + LegalizeFrameIndex(TFI, DAG, Lo, FrameOffset); + Hi = DAG.getConstant(1, MVT::i8); + Offset += FrameOffset; + return; + } else if (TFI.getOpcode() == ISD::TargetExternalSymbol) { + // FrameIndex has already been expanded. + // Now just make use of its expansion + Lo = TFI; + Hi = DAG.getConstant(1, MVT::i8); + SDValue FOffset = Ptr.getOperand(0).getOperand(1); + assert (FOffset.getOpcode() == ISD::Constant && + "Invalid operand of PIC16ISD::Lo"); + Offset += dyn_cast<ConstantSDNode>(FOffset)->getZExtValue(); + return; + } + } + + if (isDirectAddress(Ptr) && !isRomAddress(Ptr)) { + // Direct addressing case for RAM variables. The Hi part is constant + // and the Lo part is the TGA itself. + Lo = Ptr.getOperand(0).getOperand(0); + + // For direct addresses Hi is a constant. Value 1 for the constant + // signifies that banksel needs to generated for it. Value 0 for + // the constant signifies that banksel does not need to be generated + // for it. Mark it as 1 now and optimize later. + Hi = DAG.getConstant(1, MVT::i8); + return; + } + + // Indirect addresses. Get the hi and lo parts of ptr. + GetExpandedParts(Ptr, DAG, Lo, Hi); + + // Put the hi and lo parts into FSR. + Lo = DAG.getNode(PIC16ISD::MTLO, dl, MVT::i8, Lo); + Hi = DAG.getNode(PIC16ISD::MTHI, dl, MVT::i8, Hi); + + return; +} + +SDValue PIC16TargetLowering::ExpandLoad(SDNode *N, SelectionDAG &DAG) const { + LoadSDNode *LD = dyn_cast<LoadSDNode>(SDValue(N, 0)); + SDValue Chain = LD->getChain(); + SDValue Ptr = LD->getBasePtr(); + DebugLoc dl = LD->getDebugLoc(); + + SDValue Load, Offset; + SDVTList Tys; + EVT VT, NewVT; + SDValue PtrLo, PtrHi; + unsigned LoadOffset; + + // Legalize direct/indirect addresses. This will give the lo and hi parts + // of the address and the offset. + LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, LoadOffset, dl); + + // Load from the pointer (direct address or FSR) + VT = N->getValueType(0); + unsigned NumLoads = VT.getSizeInBits() / 8; + std::vector<SDValue> PICLoads; + unsigned iter; + EVT MemVT = LD->getMemoryVT(); + if(ISD::isNON_EXTLoad(N)) { + for (iter=0; iter<NumLoads ; ++iter) { + // Add the pointer offset if any + Offset = DAG.getConstant(iter + LoadOffset, MVT::i8); + Tys = DAG.getVTList(MVT::i8, MVT::Other); + Load = DAG.getNode(PIC16ISD::PIC16Load, dl, Tys, Chain, PtrLo, PtrHi, + Offset); + PICLoads.push_back(Load); + } + } else { + // If it is extended load then use PIC16Load for Memory Bytes + // and for all extended bytes perform action based on type of + // extention - i.e. SignExtendedLoad or ZeroExtendedLoad + + + // For extended loads this is the memory value type + // i.e. without any extension + EVT MemVT = LD->getMemoryVT(); + unsigned MemBytes = MemVT.getSizeInBits() / 8; + // if MVT::i1 is extended to MVT::i8 then MemBytes will be zero + // So set it to one + if (MemBytes == 0) MemBytes = 1; + + unsigned ExtdBytes = VT.getSizeInBits() / 8; + Offset = DAG.getConstant(LoadOffset, MVT::i8); + + Tys = DAG.getVTList(MVT::i8, MVT::Other); + // For MemBytes generate PIC16Load with proper offset + for (iter=0; iter < MemBytes; ++iter) { + // Add the pointer offset if any + Offset = DAG.getConstant(iter + LoadOffset, MVT::i8); + Load = DAG.getNode(PIC16ISD::PIC16Load, dl, Tys, Chain, PtrLo, PtrHi, + Offset); + PICLoads.push_back(Load); + } + + // For SignExtendedLoad + if (ISD::isSEXTLoad(N)) { + // For all ExtdBytes use the Right Shifted(Arithmetic) Value of the + // highest MemByte + SDValue SRA = DAG.getNode(ISD::SRA, dl, MVT::i8, Load, + DAG.getConstant(7, MVT::i8)); + for (iter=MemBytes; iter<ExtdBytes; ++iter) { + PICLoads.push_back(SRA); + } + } else if (ISD::isZEXTLoad(N) || ISD::isEXTLoad(N)) { + //} else if (ISD::isZEXTLoad(N)) { + // ZeroExtendedLoad -- For all ExtdBytes use constant 0 + SDValue ConstZero = DAG.getConstant(0, MVT::i8); + for (iter=MemBytes; iter<ExtdBytes; ++iter) { + PICLoads.push_back(ConstZero); + } + } + } + SDValue BP; + + if (VT == MVT::i8) { + // Operand of Load is illegal -- Load itself is legal + return PICLoads[0]; + } + else if (VT == MVT::i16) { + BP = DAG.getNode(ISD::BUILD_PAIR, dl, VT, PICLoads[0], PICLoads[1]); + if ((MemVT == MVT::i8) || (MemVT == MVT::i1)) + Chain = getChain(PICLoads[0]); + else + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[0]), getChain(PICLoads[1])); + } else if (VT == MVT::i32) { + SDValue BPs[2]; + BPs[0] = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, + PICLoads[0], PICLoads[1]); + BPs[1] = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, + PICLoads[2], PICLoads[3]); + BP = DAG.getNode(ISD::BUILD_PAIR, dl, VT, BPs[0], BPs[1]); + if ((MemVT == MVT::i8) || (MemVT == MVT::i1)) + Chain = getChain(PICLoads[0]); + else if (MemVT == MVT::i16) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[0]), getChain(PICLoads[1])); + else { + SDValue Chains[2]; + Chains[0] = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[0]), getChain(PICLoads[1])); + Chains[1] = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[2]), getChain(PICLoads[3])); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + Chains[0], Chains[1]); + } + } + Tys = DAG.getVTList(VT, MVT::Other); + return DAG.getNode(ISD::MERGE_VALUES, dl, Tys, BP, Chain); +} + +SDValue PIC16TargetLowering::LowerShift(SDValue Op, SelectionDAG &DAG) const { + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal shift to lower"); + + SDNode *N = Op.getNode(); + SDValue Value = N->getOperand(0); + SDValue Amt = N->getOperand(1); + PIC16ISD::PIC16Libcall CallCode; + switch (N->getOpcode()) { + case ISD::SRA: + CallCode = PIC16ISD::SRA_I8; + break; + case ISD::SHL: + CallCode = PIC16ISD::SLL_I8; + break; + case ISD::SRL: + CallCode = PIC16ISD::SRL_I8; + break; + default: + assert ( 0 && "This shift is not implemented yet."); + return SDValue(); + } + SmallVector<SDValue, 2> Ops(2); + Ops[0] = Value; + Ops[1] = Amt; + SDValue Call = MakePIC16Libcall(CallCode, N->getValueType(0), &Ops[0], 2, + true, DAG, N->getDebugLoc()); + return Call; +} + +SDValue PIC16TargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const { + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal multiply to lower"); + + SDNode *N = Op.getNode(); + SmallVector<SDValue, 2> Ops(2); + Ops[0] = N->getOperand(0); + Ops[1] = N->getOperand(1); + SDValue Call = MakePIC16Libcall(PIC16ISD::MUL_I8, N->getValueType(0), + &Ops[0], 2, true, DAG, N->getDebugLoc()); + return Call; +} + +void +PIC16TargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) const { + SDValue Op = SDValue(N, 0); + SDValue Res; + unsigned i; + switch (Op.getOpcode()) { + case ISD::LOAD: + Res = ExpandLoad(Op.getNode(), DAG); break; + default: { + // All other operations are handled in LowerOperation. + Res = LowerOperation(Op, DAG); + if (Res.getNode()) + Results.push_back(Res); + + return; + } + } + + N = Res.getNode(); + unsigned NumValues = N->getNumValues(); + for (i = 0; i < NumValues ; i++) { + Results.push_back(SDValue(N, i)); + } +} + +SDValue PIC16TargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::ADD: + case ISD::ADDC: + case ISD::ADDE: + return LowerADD(Op, DAG); + case ISD::SUB: + case ISD::SUBC: + case ISD::SUBE: + return LowerSUB(Op, DAG); + case ISD::LOAD: + return ExpandLoad(Op.getNode(), DAG); + case ISD::STORE: + return ExpandStore(Op.getNode(), DAG); + case ISD::MUL: + return LowerMUL(Op, DAG); + case ISD::SHL: + case ISD::SRA: + case ISD::SRL: + return LowerShift(Op, DAG); + case ISD::OR: + case ISD::AND: + case ISD::XOR: + return LowerBinOp(Op, DAG); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + } + return SDValue(); +} + +SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op, + SelectionDAG &DAG, + DebugLoc dl) const { + assert (Op.getValueType() == MVT::i8 + && "illegal value type to store on stack."); + + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + const std::string FuncName = Func->getName(); + + + // Put the value on stack. + // Get a stack slot index and convert to es. + int FI = MF.getFrameInfo()->CreateStackObject(1, 1, false); + const char *tmpName = ESNames::createESName(PAN::getTempdataLabel(FuncName)); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + + // Store the value to ES. + SDValue Store = DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, + DAG.getEntryNode(), + Op, ES, + DAG.getConstant (1, MVT::i8), // Banksel. + DAG.getConstant (GetTmpOffsetForFI(FI, 1, MF), + MVT::i8)); + + // Load the value from ES. + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other); + SDValue Load = DAG.getNode(PIC16ISD::PIC16Load, dl, Tys, Store, + ES, DAG.getConstant (1, MVT::i8), + DAG.getConstant (GetTmpOffsetForFI(FI, 1, MF), + MVT::i8)); + + return Load.getValue(0); +} + +SDValue PIC16TargetLowering:: +LowerIndirectCallArguments(SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG) const { + unsigned NumOps = Outs.size(); + + // If call has no arguments then do nothing and return. + if (NumOps == 0) + return Chain; + + std::vector<SDValue> Ops; + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag); + SDValue Arg, StoreRet; + + // For PIC16 ABI the arguments come after the return value. + unsigned RetVals = Ins.size(); + for (unsigned i = 0, ArgOffset = RetVals; i < NumOps; i++) { + // Get the arguments + Arg = Outs[i].Val; + + Ops.clear(); + Ops.push_back(Chain); + Ops.push_back(Arg); + Ops.push_back(DataAddr_Lo); + Ops.push_back(DataAddr_Hi); + Ops.push_back(DAG.getConstant(ArgOffset, MVT::i8)); + Ops.push_back(InFlag); + + StoreRet = DAG.getNode (PIC16ISD::PIC16StWF, dl, Tys, &Ops[0], Ops.size()); + + Chain = getChain(StoreRet); + InFlag = getOutFlag(StoreRet); + ArgOffset++; + } + return Chain; +} + +SDValue PIC16TargetLowering:: +LowerDirectCallArguments(SDValue ArgLabel, SDValue Chain, SDValue InFlag, + const SmallVectorImpl<ISD::OutputArg> &Outs, + DebugLoc dl, SelectionDAG &DAG) const { + unsigned NumOps = Outs.size(); + std::string Name; + SDValue Arg, StoreAt; + EVT ArgVT; + unsigned Size=0; + + // If call has no arguments then do nothing and return. + if (NumOps == 0) + return Chain; + + // FIXME: This portion of code currently assumes only + // primitive types being passed as arguments. + + // Legalize the address before use + SDValue PtrLo, PtrHi; + unsigned AddressOffset; + int StoreOffset = 0; + LegalizeAddress(ArgLabel, DAG, PtrLo, PtrHi, AddressOffset, dl); + SDValue StoreRet; + + std::vector<SDValue> Ops; + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag); + for (unsigned i=0, Offset = 0; i<NumOps; i++) { + // Get the argument + Arg = Outs[i].Val; + StoreOffset = (Offset + AddressOffset); + + // Store the argument on frame + + Ops.clear(); + Ops.push_back(Chain); + Ops.push_back(Arg); + Ops.push_back(PtrLo); + Ops.push_back(PtrHi); + Ops.push_back(DAG.getConstant(StoreOffset, MVT::i8)); + Ops.push_back(InFlag); + + StoreRet = DAG.getNode (PIC16ISD::PIC16StWF, dl, Tys, &Ops[0], Ops.size()); + + Chain = getChain(StoreRet); + InFlag = getOutFlag(StoreRet); + + // Update the frame offset to be used for next argument + ArgVT = Arg.getValueType(); + Size = ArgVT.getSizeInBits(); + Size = Size/8; // Calculate size in bytes + Offset += Size; // Increase the frame offset + } + return Chain; +} + +SDValue PIC16TargetLowering:: +LowerIndirectCallReturn(SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + unsigned RetVals = Ins.size(); + + // If call does not have anything to return + // then do nothing and go back. + if (RetVals == 0) + return Chain; + + // Call has something to return + SDValue LoadRet; + + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag); + for(unsigned i=0;i<RetVals;i++) { + LoadRet = DAG.getNode(PIC16ISD::PIC16LdWF, dl, Tys, Chain, DataAddr_Lo, + DataAddr_Hi, DAG.getConstant(i, MVT::i8), + InFlag); + InFlag = getOutFlag(LoadRet); + Chain = getChain(LoadRet); + InVals.push_back(LoadRet); + } + return Chain; +} + +SDValue PIC16TargetLowering:: +LowerDirectCallReturn(SDValue RetLabel, SDValue Chain, SDValue InFlag, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + + // Currently handling primitive types only. They will come in + // i8 parts + unsigned RetVals = Ins.size(); + + // Return immediately if the return type is void + if (RetVals == 0) + return Chain; + + // Call has something to return + + // Legalize the address before use + SDValue LdLo, LdHi; + unsigned LdOffset; + LegalizeAddress(RetLabel, DAG, LdLo, LdHi, LdOffset, dl); + + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag); + SDValue LoadRet; + + for(unsigned i=0, Offset=0;i<RetVals;i++) { + + LoadRet = DAG.getNode(PIC16ISD::PIC16LdWF, dl, Tys, Chain, LdLo, LdHi, + DAG.getConstant(LdOffset + Offset, MVT::i8), + InFlag); + + InFlag = getOutFlag(LoadRet); + + Chain = getChain(LoadRet); + Offset++; + InVals.push_back(LoadRet); + } + + return Chain; +} + +SDValue +PIC16TargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + DebugLoc dl, SelectionDAG &DAG) const { + + // Number of values to return + unsigned NumRet = Outs.size(); + + // Function returns value always on stack with the offset starting + // from 0 + MachineFunction &MF = DAG.getMachineFunction(); + const Function *F = MF.getFunction(); + std::string FuncName = F->getName(); + + const char *tmpName = ESNames::createESName(PAN::getFrameLabel(FuncName)); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + SDValue BS = DAG.getConstant(1, MVT::i8); + SDValue RetVal; + for(unsigned i=0;i<NumRet; ++i) { + RetVal = Outs[i].Val; + Chain = DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, RetVal, + ES, BS, + DAG.getConstant (i, MVT::i8)); + + } + return DAG.getNode(PIC16ISD::RET, dl, MVT::Other, Chain); +} + +void PIC16TargetLowering:: +GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain, + SDValue &DataAddr_Lo, SDValue &DataAddr_Hi, + SelectionDAG &DAG) const { + assert (Callee.getOpcode() == PIC16ISD::PIC16Connect + && "Don't know what to do of such callee!!"); + SDValue ZeroOperand = DAG.getConstant(0, MVT::i8); + SDValue SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand); + Chain = getChain(SeqStart); + SDValue OperFlag = getOutFlag(SeqStart); // To manage the data dependency + + // Get the Lo and Hi part of code address + SDValue Lo = Callee.getOperand(0); + SDValue Hi = Callee.getOperand(1); + + SDValue Data_Lo, Data_Hi; + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag); + // Subtract 2 from Address to get the Lower part of DataAddress. + SDVTList VTList = DAG.getVTList(MVT::i8, MVT::Flag); + Data_Lo = DAG.getNode(ISD::SUBC, dl, VTList, Lo, + DAG.getConstant(2, MVT::i8)); + SDValue Ops[3] = { Hi, DAG.getConstant(0, MVT::i8), Data_Lo.getValue(1)}; + Data_Hi = DAG.getNode(ISD::SUBE, dl, VTList, Ops, 3); + SDValue PCLATH = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, Data_Hi); + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Data_Lo, PCLATH); + SDValue Call = DAG.getNode(PIC16ISD::CALLW, dl, Tys, Chain, Callee, + OperFlag); + Chain = getChain(Call); + OperFlag = getOutFlag(Call); + SDValue SeqEnd = DAG.getCALLSEQ_END(Chain, ZeroOperand, ZeroOperand, + OperFlag); + Chain = getChain(SeqEnd); + OperFlag = getOutFlag(SeqEnd); + + // Low part of Data Address + DataAddr_Lo = DAG.getNode(PIC16ISD::MTLO, dl, MVT::i8, Call, OperFlag); + + // Make the second call. + SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand); + Chain = getChain(SeqStart); + OperFlag = getOutFlag(SeqStart); // To manage the data dependency + + // Subtract 1 from Address to get high part of data address. + Data_Lo = DAG.getNode(ISD::SUBC, dl, VTList, Lo, + DAG.getConstant(1, MVT::i8)); + SDValue HiOps[3] = { Hi, DAG.getConstant(0, MVT::i8), Data_Lo.getValue(1)}; + Data_Hi = DAG.getNode(ISD::SUBE, dl, VTList, HiOps, 3); + PCLATH = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, Data_Hi); + + // Use new Lo to make another CALLW + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Data_Lo, PCLATH); + Call = DAG.getNode(PIC16ISD::CALLW, dl, Tys, Chain, Callee, OperFlag); + Chain = getChain(Call); + OperFlag = getOutFlag(Call); + SeqEnd = DAG.getCALLSEQ_END(Chain, ZeroOperand, ZeroOperand, + OperFlag); + Chain = getChain(SeqEnd); + OperFlag = getOutFlag(SeqEnd); + // Hi part of Data Address + DataAddr_Hi = DAG.getNode(PIC16ISD::MTHI, dl, MVT::i8, Call, OperFlag); +} + +SDValue +PIC16TargetLowering::LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // PIC16 target does not yet support tail call optimization. + isTailCall = false; + + assert(Callee.getValueType() == MVT::i16 && + "Don't know how to legalize this call node!!!"); + + // The flag to track if this is a direct or indirect call. + bool IsDirectCall = true; + unsigned RetVals = Ins.size(); + unsigned NumArgs = Outs.size(); + + SDValue DataAddr_Lo, DataAddr_Hi; + if (!isa<GlobalAddressSDNode>(Callee) && + !isa<ExternalSymbolSDNode>(Callee)) { + IsDirectCall = false; // This is indirect call + + // If this is an indirect call then to pass the arguments + // and read the return value back, we need the data address + // of the function being called. + // To get the data address two more calls need to be made. + + // Come here for indirect calls + SDValue Lo, Hi; + // Indirect addresses. Get the hi and lo parts of ptr. + GetExpandedParts(Callee, DAG, Lo, Hi); + // Connect Lo and Hi parts of the callee with the PIC16Connect + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Lo, Hi); + + // Read DataAddress only if we have to pass arguments or + // read return value. + if ((RetVals > 0) || (NumArgs > 0)) + GetDataAddress(dl, Callee, Chain, DataAddr_Lo, DataAddr_Hi, DAG); + } + + SDValue ZeroOperand = DAG.getConstant(0, MVT::i8); + + // Start the call sequence. + // Carring the Constant 0 along the CALLSEQSTART + // because there is nothing else to carry. + SDValue SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand); + Chain = getChain(SeqStart); + SDValue OperFlag = getOutFlag(SeqStart); // To manage the data dependency + std::string Name; + + // For any direct call - callee will be GlobalAddressNode or + // ExternalSymbol + SDValue ArgLabel, RetLabel; + if (IsDirectCall) { + // Considering the GlobalAddressNode case here. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + const GlobalValue *GV = G->getGlobal(); + Callee = DAG.getTargetGlobalAddress(GV, MVT::i8); + Name = G->getGlobal()->getName(); + } else {// Considering the ExternalSymbol case here + ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee); + Callee = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8); + Name = ES->getSymbol(); + } + + // Label for argument passing + const char *argFrame = ESNames::createESName(PAN::getArgsLabel(Name)); + ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8); + + // Label for reading return value + const char *retName = ESNames::createESName(PAN::getRetvalLabel(Name)); + RetLabel = DAG.getTargetExternalSymbol(retName, MVT::i8); + } else { + // if indirect call + SDValue CodeAddr_Lo = Callee.getOperand(0); + SDValue CodeAddr_Hi = Callee.getOperand(1); + + /*CodeAddr_Lo = DAG.getNode(ISD::ADD, dl, MVT::i8, CodeAddr_Lo, + DAG.getConstant(2, MVT::i8));*/ + + // move Hi part in PCLATH + CodeAddr_Hi = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, CodeAddr_Hi); + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, CodeAddr_Lo, + CodeAddr_Hi); + } + + // Pass the argument to function before making the call. + SDValue CallArgs; + if (IsDirectCall) { + CallArgs = LowerDirectCallArguments(ArgLabel, Chain, OperFlag, + Outs, dl, DAG); + Chain = getChain(CallArgs); + OperFlag = getOutFlag(CallArgs); + } else { + CallArgs = LowerIndirectCallArguments(Chain, OperFlag, DataAddr_Lo, + DataAddr_Hi, Outs, Ins, dl, DAG); + Chain = getChain(CallArgs); + OperFlag = getOutFlag(CallArgs); + } + + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag); + SDValue PICCall = DAG.getNode(PIC16ISD::CALL, dl, Tys, Chain, Callee, + OperFlag); + Chain = getChain(PICCall); + OperFlag = getOutFlag(PICCall); + + + // Carrying the Constant 0 along the CALLSEQSTART + // because there is nothing else to carry. + SDValue SeqEnd = DAG.getCALLSEQ_END(Chain, ZeroOperand, ZeroOperand, + OperFlag); + Chain = getChain(SeqEnd); + OperFlag = getOutFlag(SeqEnd); + + // Lower the return value reading after the call. + if (IsDirectCall) + return LowerDirectCallReturn(RetLabel, Chain, OperFlag, + Ins, dl, DAG, InVals); + else + return LowerIndirectCallReturn(Chain, OperFlag, DataAddr_Lo, + DataAddr_Hi, Ins, dl, DAG, InVals); +} + +bool PIC16TargetLowering::isDirectLoad(const SDValue Op) const { + if (Op.getOpcode() == PIC16ISD::PIC16Load) + if (Op.getOperand(1).getOpcode() == ISD::TargetGlobalAddress + || Op.getOperand(1).getOpcode() == ISD::TargetExternalSymbol) + return true; + return false; +} + +// NeedToConvertToMemOp - Returns true if one of the operands of the +// operation 'Op' needs to be put into memory. Also returns the +// operand no. of the operand to be converted in 'MemOp'. Remember, PIC16 has +// no instruction that can operation on two registers. Most insns take +// one register and one memory operand (addwf) / Constant (addlw). +bool PIC16TargetLowering::NeedToConvertToMemOp(SDValue Op, unsigned &MemOp, + SelectionDAG &DAG) const { + // If one of the operand is a constant, return false. + if (Op.getOperand(0).getOpcode() == ISD::Constant || + Op.getOperand(1).getOpcode() == ISD::Constant) + return false; + + // Return false if one of the operands is already a direct + // load and that operand has only one use. + if (isDirectLoad(Op.getOperand(0))) { + if (Op.getOperand(0).hasOneUse()) { + // Legal and profitable folding check uses the NodeId of DAG nodes. + // This NodeId is assigned by topological order. Therefore first + // assign topological order then perform legal and profitable check. + // Note:- Though this ordering is done before begining with legalization, + // newly added node during legalization process have NodeId=-1 (NewNode) + // therefore before performing any check proper ordering of the node is + // required. + DAG.AssignTopologicalOrder(); + + // Direct load operands are folded in binary operations. But before folding + // verify if this folding is legal. Fold only if it is legal otherwise + // convert this direct load to a separate memory operation. + if (SelectionDAGISel::IsLegalToFold(Op.getOperand(0), + Op.getNode(), Op.getNode(), + CodeGenOpt::Default)) + return false; + else + MemOp = 0; + } + } + + // For operations that are non-cummutative there is no need to check + // for right operand because folding right operand may result in + // incorrect operation. + if (! SelectionDAG::isCommutativeBinOp(Op.getOpcode())) + return true; + + if (isDirectLoad(Op.getOperand(1))) { + if (Op.getOperand(1).hasOneUse()) { + // Legal and profitable folding check uses the NodeId of DAG nodes. + // This NodeId is assigned by topological order. Therefore first + // assign topological order then perform legal and profitable check. + // Note:- Though this ordering is done before begining with legalization, + // newly added node during legalization process have NodeId=-1 (NewNode) + // therefore before performing any check proper ordering of the node is + // required. + DAG.AssignTopologicalOrder(); + + // Direct load operands are folded in binary operations. But before folding + // verify if this folding is legal. Fold only if it is legal otherwise + // convert this direct load to a separate memory operation. + if (SelectionDAGISel::IsLegalToFold(Op.getOperand(1), + Op.getNode(), Op.getNode(), + CodeGenOpt::Default)) + return false; + else + MemOp = 1; + } + } + return true; +} + +// LowerBinOp - Lower a commutative binary operation that does not +// affect status flag carry. +SDValue PIC16TargetLowering::LowerBinOp(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal Op to lower"); + + unsigned MemOp = 1; + if (NeedToConvertToMemOp(Op, MemOp, DAG)) { + // Put one value on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(MemOp), DAG, dl); + + return DAG.getNode(Op.getOpcode(), dl, MVT::i8, Op.getOperand(MemOp ^ 1), + NewVal); + } + else { + return Op; + } +} + +// LowerADD - Lower all types of ADD operations including the ones +// that affects carry. +SDValue PIC16TargetLowering::LowerADD(SDValue Op, SelectionDAG &DAG) const { + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal add to lower"); + DebugLoc dl = Op.getDebugLoc(); + unsigned MemOp = 1; + if (NeedToConvertToMemOp(Op, MemOp, DAG)) { + // Put one value on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(MemOp), DAG, dl); + + // ADDC and ADDE produce two results. + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); + + // ADDE has three operands, the last one is the carry bit. + if (Op.getOpcode() == ISD::ADDE) + return DAG.getNode(Op.getOpcode(), dl, Tys, Op.getOperand(MemOp ^ 1), + NewVal, Op.getOperand(2)); + // ADDC has two operands. + else if (Op.getOpcode() == ISD::ADDC) + return DAG.getNode(Op.getOpcode(), dl, Tys, Op.getOperand(MemOp ^ 1), + NewVal); + // ADD it is. It produces only one result. + else + return DAG.getNode(Op.getOpcode(), dl, MVT::i8, Op.getOperand(MemOp ^ 1), + NewVal); + } + else + return Op; +} + +SDValue PIC16TargetLowering::LowerSUB(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal sub to lower"); + unsigned MemOp = 1; + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); + + // Since we don't have an instruction for X - c , + // we can change it to X + (-c) + ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1)); + if (C && (Op.getOpcode() == ISD::SUB)) + { + return DAG.getNode(ISD::ADD, + dl, MVT::i8, Op.getOperand(0), + DAG.getConstant(0-(C->getZExtValue()), MVT::i8)); + } + + if (NeedToConvertToMemOp(Op, MemOp, DAG) || + (isDirectLoad(Op.getOperand(1)) && + (!isDirectLoad(Op.getOperand(0))) && + (Op.getOperand(0).getOpcode() != ISD::Constant))) + { + // Put first operand on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(0), DAG, dl); + + switch (Op.getOpcode()) { + default: + assert (0 && "Opcode unknown."); + case ISD::SUBE: + return DAG.getNode(Op.getOpcode(), + dl, Tys, NewVal, Op.getOperand(1), + Op.getOperand(2)); + break; + case ISD::SUBC: + return DAG.getNode(Op.getOpcode(), + dl, Tys, NewVal, Op.getOperand(1)); + break; + case ISD::SUB: + return DAG.getNode(Op.getOpcode(), + dl, MVT::i8, NewVal, Op.getOperand(1)); + break; + } + } + else + return Op; +} + +void PIC16TargetLowering::InitReservedFrameCount(const Function *F, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + + unsigned NumArgs = F->arg_size(); + + bool isVoidFunc = (F->getReturnType()->getTypeID() == Type::VoidTyID); + + if (isVoidFunc) + FuncInfo->setReservedFrameCount(NumArgs); + else + FuncInfo->setReservedFrameCount(NumArgs + 1); +} + +// LowerFormalArguments - Argument values are loaded from the +// <fname>.args + offset. All arguments are already broken to leaglized +// types, so the offset just runs from 0 to NumArgVals - 1. + +SDValue +PIC16TargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + unsigned NumArgVals = Ins.size(); + + // Get the callee's name to create the <fname>.args label to pass args. + MachineFunction &MF = DAG.getMachineFunction(); + const Function *F = MF.getFunction(); + std::string FuncName = F->getName(); + + // Reset the map of FI and TmpOffset + ResetTmpOffsetMap(DAG); + // Initialize the ReserveFrameCount + InitReservedFrameCount(F, DAG); + + // Create the <fname>.args external symbol. + const char *tmpName = ESNames::createESName(PAN::getArgsLabel(FuncName)); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + + // Load arg values from the label + offset. + SDVTList VTs = DAG.getVTList (MVT::i8, MVT::Other); + SDValue BS = DAG.getConstant(1, MVT::i8); + for (unsigned i = 0; i < NumArgVals ; ++i) { + SDValue Offset = DAG.getConstant(i, MVT::i8); + SDValue PICLoad = DAG.getNode(PIC16ISD::PIC16LdArg, dl, VTs, Chain, ES, BS, + Offset); + Chain = getChain(PICLoad); + InVals.push_back(PICLoad); + } + + return Chain; +} + +// Perform DAGCombine of PIC16Load. +// FIXME - Need a more elaborate comment here. +SDValue PIC16TargetLowering:: +PerformPIC16LoadCombine(SDNode *N, DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + SDValue Chain = N->getOperand(0); + if (N->hasNUsesOfValue(0, 0)) { + DAG.ReplaceAllUsesOfValueWith(SDValue(N,1), Chain); + } + return SDValue(); +} + +// For all the functions with arguments some STORE nodes are generated +// that store the argument on the frameindex. However in PIC16 the arguments +// are passed on stack only. Therefore these STORE nodes are redundant. +// To remove these STORE nodes will be removed in PerformStoreCombine +// +// Currently this function is doint nothing and will be updated for removing +// unwanted store operations +SDValue PIC16TargetLowering:: +PerformStoreCombine(SDNode *N, DAGCombinerInfo &DCI) const { + return SDValue(N, 0); + /* + // Storing an undef value is of no use, so remove it + if (isStoringUndef(N, Chain, DAG)) { + return Chain; // remove the store and return the chain + } + //else everything is ok. + return SDValue(N, 0); + */ +} + +SDValue PIC16TargetLowering::PerformDAGCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + switch (N->getOpcode()) { + case ISD::STORE: + return PerformStoreCombine(N, DCI); + case PIC16ISD::PIC16Load: + return PerformPIC16LoadCombine(N, DCI); + } + return SDValue(); +} + +static PIC16CC::CondCodes IntCCToPIC16CC(ISD::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code!"); + case ISD::SETNE: return PIC16CC::NE; + case ISD::SETEQ: return PIC16CC::EQ; + case ISD::SETGT: return PIC16CC::GT; + case ISD::SETGE: return PIC16CC::GE; + case ISD::SETLT: return PIC16CC::LT; + case ISD::SETLE: return PIC16CC::LE; + case ISD::SETULT: return PIC16CC::ULT; + case ISD::SETULE: return PIC16CC::ULE; + case ISD::SETUGE: return PIC16CC::UGE; + case ISD::SETUGT: return PIC16CC::UGT; + } +} + +// Look at LHS/RHS/CC and see if they are a lowered setcc instruction. If so +// set LHS/RHS and SPCC to the LHS/RHS of the setcc and SPCC to the condition. +static void LookThroughSetCC(SDValue &LHS, SDValue &RHS, + ISD::CondCode CC, unsigned &SPCC) { + if (isa<ConstantSDNode>(RHS) && + cast<ConstantSDNode>(RHS)->getZExtValue() == 0 && + CC == ISD::SETNE && + (LHS.getOpcode() == PIC16ISD::SELECT_ICC && + LHS.getOperand(3).getOpcode() == PIC16ISD::SUBCC) && + isa<ConstantSDNode>(LHS.getOperand(0)) && + isa<ConstantSDNode>(LHS.getOperand(1)) && + cast<ConstantSDNode>(LHS.getOperand(0))->getZExtValue() == 1 && + cast<ConstantSDNode>(LHS.getOperand(1))->getZExtValue() == 0) { + SDValue CMPCC = LHS.getOperand(3); + SPCC = cast<ConstantSDNode>(LHS.getOperand(2))->getZExtValue(); + LHS = CMPCC.getOperand(0); + RHS = CMPCC.getOperand(1); + } +} + +// Returns appropriate CMP insn and corresponding condition code in PIC16CC +SDValue PIC16TargetLowering::getPIC16Cmp(SDValue LHS, SDValue RHS, + unsigned CC, SDValue &PIC16CC, + SelectionDAG &DAG, DebugLoc dl) const { + PIC16CC::CondCodes CondCode = (PIC16CC::CondCodes) CC; + + // PIC16 sub is literal - W. So Swap the operands and condition if needed. + // i.e. a < 12 can be rewritten as 12 > a. + if (RHS.getOpcode() == ISD::Constant) { + + SDValue Tmp = LHS; + LHS = RHS; + RHS = Tmp; + + switch (CondCode) { + default: break; + case PIC16CC::LT: + CondCode = PIC16CC::GT; + break; + case PIC16CC::GT: + CondCode = PIC16CC::LT; + break; + case PIC16CC::ULT: + CondCode = PIC16CC::UGT; + break; + case PIC16CC::UGT: + CondCode = PIC16CC::ULT; + break; + case PIC16CC::GE: + CondCode = PIC16CC::LE; + break; + case PIC16CC::LE: + CondCode = PIC16CC::GE; + break; + case PIC16CC::ULE: + CondCode = PIC16CC::UGE; + break; + case PIC16CC::UGE: + CondCode = PIC16CC::ULE; + break; + } + } + + PIC16CC = DAG.getConstant(CondCode, MVT::i8); + + // These are signed comparisons. + SDValue Mask = DAG.getConstant(128, MVT::i8); + if (isSignedComparison(CondCode)) { + LHS = DAG.getNode (ISD::XOR, dl, MVT::i8, LHS, Mask); + RHS = DAG.getNode (ISD::XOR, dl, MVT::i8, RHS, Mask); + } + + SDVTList VTs = DAG.getVTList (MVT::i8, MVT::Flag); + // We can use a subtract operation to set the condition codes. But + // we need to put one operand in memory if required. + // Nothing to do if the first operand is already a valid type (direct load + // for subwf and literal for sublw) and it is used by this operation only. + if ((LHS.getOpcode() == ISD::Constant || isDirectLoad(LHS)) + && LHS.hasOneUse()) + return DAG.getNode(PIC16ISD::SUBCC, dl, VTs, LHS, RHS); + + // else convert the first operand to mem. + LHS = ConvertToMemOperand (LHS, DAG, dl); + return DAG.getNode(PIC16ISD::SUBCC, dl, VTs, LHS, RHS); +} + + +SDValue PIC16TargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); + SDValue TrueVal = Op.getOperand(2); + SDValue FalseVal = Op.getOperand(3); + unsigned ORIGCC = ~0; + DebugLoc dl = Op.getDebugLoc(); + + // If this is a select_cc of a "setcc", and if the setcc got lowered into + // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values. + // i.e. + // A setcc: lhs, rhs, cc is expanded by llvm to + // select_cc: result of setcc, 0, 1, 0, setne + // We can think of it as: + // select_cc: lhs, rhs, 1, 0, cc + LookThroughSetCC(LHS, RHS, CC, ORIGCC); + if (ORIGCC == ~0U) ORIGCC = IntCCToPIC16CC (CC); + + SDValue PIC16CC; + SDValue Cmp = getPIC16Cmp(LHS, RHS, ORIGCC, PIC16CC, DAG, dl); + + return DAG.getNode (PIC16ISD::SELECT_ICC, dl, TrueVal.getValueType(), TrueVal, + FalseVal, PIC16CC, Cmp.getValue(1)); +} + +MachineBasicBlock * +PIC16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + unsigned CC = (PIC16CC::CondCodes)MI->getOperand(3).getImm(); + DebugLoc dl = MI->getDebugLoc(); + + // To "insert" a SELECT_CC instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // [f]bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + BuildMI(BB, dl, TII.get(PIC16::pic16brcond)).addMBB(sinkMBB).addImm(CC); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Update machine-CFG edges by first adding all successors of the current + // block to the new block which will contain the Phi node for the select. + for (MachineBasicBlock::succ_iterator I = BB->succ_begin(), + E = BB->succ_end(); I != E; ++I) + sinkMBB->addSuccessor(*I); + // Next, remove all successors of the current block, and add the true + // and fallthrough blocks as its successors. + while (!BB->succ_empty()) + BB->removeSuccessor(BB->succ_begin()); + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = sinkMBB; + BuildMI(BB, dl, TII.get(PIC16::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + return BB; +} + + +SDValue PIC16TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); // LHS of the condition. + SDValue RHS = Op.getOperand(3); // RHS of the condition. + SDValue Dest = Op.getOperand(4); // BB to jump to + unsigned ORIGCC = ~0; + DebugLoc dl = Op.getDebugLoc(); + + // If this is a br_cc of a "setcc", and if the setcc got lowered into + // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values. + LookThroughSetCC(LHS, RHS, CC, ORIGCC); + if (ORIGCC == ~0U) ORIGCC = IntCCToPIC16CC (CC); + + // Get the Compare insn and condition code. + SDValue PIC16CC; + SDValue Cmp = getPIC16Cmp(LHS, RHS, ORIGCC, PIC16CC, DAG, dl); + + return DAG.getNode(PIC16ISD::BRCOND, dl, MVT::Other, Chain, Dest, PIC16CC, + Cmp.getValue(1)); +} + |