Added missing libcalls for floating point to int conversions.
[oota-llvm.git] / lib / Target / PIC16 / PIC16ISelLowering.cpp
index 28cc0825525749ebb45b508323be2b2329f1661c..f113a483d692461d42e2da78217995783f2a1372 100644 (file)
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
-#include <cstdio>
 
 
 using namespace llvm;
 
+static const char *getIntrinsicName(unsigned opcode) {
+  std::string Basename;
+  switch(opcode) {
+  default: assert (0 && "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;
+  }
+  
+  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.
+  char *tmp = new char[Fullname.size() + 1];
+  strcpy (tmp, Fullname.c_str());
+  
+  return tmp;
+}
 
 // PIC16TargetLowering Constructor.
 PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM)
-  : TargetLowering(TM) {
-  
+  : TargetLowering(TM), TmpSize(0) {
   Subtarget = &TM.getSubtarget<PIC16Subtarget>();
 
   addRegisterClass(MVT::i8, PIC16::GPRRegisterClass);
@@ -41,24 +122,70 @@ PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM)
   setShiftAmountFlavor(Extend);
 
   // SRA library call names
-  setPIC16LibcallName(PIC16ISD::SRA_I8, "__intrinsics.sra.i8");
-  setLibcallName(RTLIB::SRA_I16, "__intrinsics.sra.i16");
-  setLibcallName(RTLIB::SRA_I32, "__intrinsics.sra.i32");
+  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, "__intrinsics.sll.i8");
-  setLibcallName(RTLIB::SHL_I16, "__intrinsics.sll.i16");
-  setLibcallName(RTLIB::SHL_I32, "__intrinsics.sll.i32");
+  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, "__intrinsics.srl.i8");
-  setLibcallName(RTLIB::SRL_I16, "__intrinsics.srl.i16");
-  setLibcallName(RTLIB::SRL_I32, "__intrinsics.srl.i32");
+  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, "__intrinsics.mul.i8");
-  setLibcallName(RTLIB::MUL_I16, "__intrinsics.mul.i16");
-  setLibcallName(RTLIB::MUL_I32, "__intrinsics.mul.i32");
+  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));
 
   setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
   setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom);
@@ -75,6 +202,7 @@ PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM)
   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);
 
@@ -142,6 +270,53 @@ PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM)
   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) {
+  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] = TmpSize; 
+  TmpSize += size;
+  return FiTmpOffsetMap[FI];
+}
+
+// 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();
@@ -156,16 +331,21 @@ MVT PIC16TargetLowering::getSetCCResultType(MVT ValType) 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; 
 PIC16LibcallNames[Call] = Name; 
 }
 
 const char *
 PIC16TargetLowering::getPIC16LibcallName(PIC16ISD::PIC16Libcall Call) {
- return PIC16LibcallNames[Call];
 return PIC16LibcallNames[Call];
 }
 
 SDValue
@@ -174,66 +354,25 @@ PIC16TargetLowering::MakePIC16Libcall(PIC16ISD::PIC16Libcall Call,
                                       unsigned NumOps, bool isSigned,
                                       SelectionDAG &DAG, DebugLoc dl) {
 
- 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().getTypeForMVT();
-   Entry.isSExt = isSigned;
-   Entry.isZExt = !isSigned;
-   Args.push_back(Entry);
- }
- SDValue Callee = DAG.getExternalSymbol(getPIC16LibcallName(Call), MVT::i8);
-
-  const Type *RetTy = RetVT.getTypeForMVT();
-  std::pair<SDValue,SDValue> CallInfo = 
-     LowerCallTo(DAG.getEntryNode(), RetTy, isSigned, !isSigned, false,
-                     false, CallingConv::C, false, Callee, Args, DAG, dl);
-
-  return CallInfo.first;
-}
+  TargetLowering::ArgListTy Args;
+  Args.reserve(NumOps);
 
-SDValue
-PIC16TargetLowering::getCurrentFrame(SelectionDAG &DAG) {
-  MachineFunction &MF = DAG.getMachineFunction();
-  const Function *Func = MF.getFunction();
-  const std::string FuncName = Func->getName();
-
-  // this is causing memory waste
-  // because for every call new memory will be allocated
-  char *tmpName = new char [strlen(FuncName.c_str()) +  6];
-  sprintf(tmpName, "%s.tmp", FuncName.c_str());
-
-  // if the external symbol of the same name already exists then
-  // it will not create the new one.
-  return DAG.getTargetExternalSymbol(tmpName, MVT::i8);
-}
+  TargetLowering::ArgListEntry Entry;
+  for (unsigned i = 0; i != NumOps; ++i) {
+    Entry.Node = Ops[i];
+    Entry.Ty = Entry.Node.getValueType().getTypeForMVT();
+    Entry.isSExt = isSigned;
+    Entry.isZExt = !isSigned;
+    Args.push_back(Entry);
+  }
+  SDValue Callee = DAG.getExternalSymbol(getPIC16LibcallName(Call), MVT::i8);
 
-void 
-PIC16TargetLowering::getCurrentFrameIndex(SelectionDAG &DAG, SDValue &ES, 
-                                        unsigned SlotSize, int &FromFI) {
-  MachineFunction &MF = DAG.getMachineFunction();
-  const Function *Func = MF.getFunction();
-  const std::string FuncName = Func->getName();
+   const Type *RetTy = RetVT.getTypeForMVT();
+   std::pair<SDValue,SDValue> CallInfo = 
+     LowerCallTo(DAG.getEntryNode(), RetTy, isSigned, !isSigned, false,
+                 false, CallingConv::C, false, Callee, Args, DAG, dl);
 
-  // this is causing memory waste
-  // because for every call new memory will be allocated
-  char *tmpName = new char [strlen(FuncName.c_str()) +  6];
-  sprintf(tmpName, "%s.tmp", FuncName.c_str());
-
-  // if the external symbol of the same name already exists then
-  // it will not create the new one.
-  ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8);
-
-  // Alignment is always 1
-  //FromFI = MF.getFrameInfo()->CreateStackObject(SlotSize, 1);
-  FromFI = MF.getFrameInfo()->CreateStackObject(1, 1);
-  int FI;
-  for(unsigned i=1;i<SlotSize; ++i) {
-    FI = MF.getFrameInfo()->CreateStackObject(1, 1);
-  }
+  return CallInfo.first;
 }
 
 const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const {
@@ -243,8 +382,11 @@ const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const {
   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";
@@ -254,6 +396,7 @@ const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const {
   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";
@@ -309,12 +452,19 @@ SDValue PIC16TargetLowering::ExpandFrameIndex(SDNode *N, SelectionDAG &DAG) {
   FrameIndexSDNode *FR = dyn_cast<FrameIndexSDNode>(SDValue(N,0));
   // FIXME there isn't really debug info here
   DebugLoc dl = FR->getDebugLoc();
-  int Index = FR->getIndex();
 
-  SDValue FI[2];
-  FI[0] = DAG.getTargetFrameIndex(Index, MVT::i8);
-  FI[1] = DAG.getTargetFrameIndex(Index + 1, MVT::i8);
-  return DAG.getNode(ISD::BUILD_PAIR, dl, N->getValueType(0), FI[0], FI[1]);
+  // 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);
 }
 
 
@@ -328,7 +478,7 @@ SDValue PIC16TargetLowering::ExpandStore(SDNode *N, SelectionDAG &DAG) {
   DebugLoc dl = N->getDebugLoc();
 
   SDValue PtrLo, PtrHi;
-  LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, StoreOffset);
+  LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, StoreOffset, dl);
  
   if (ValueType == MVT::i8) {
     return DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, Src,
@@ -418,9 +568,9 @@ SDValue PIC16TargetLowering::ExpandExternalSymbol(SDNode *N, SelectionDAG &DAG)
   DebugLoc dl = ES->getDebugLoc();
 
   SDValue TES = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8);
-
-  SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, TES);
-  SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, TES);
+  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);
 }
@@ -434,8 +584,9 @@ SDValue PIC16TargetLowering::ExpandGlobalAddress(SDNode *N, SelectionDAG &DAG) {
   SDValue TGA = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i8,
                                            G->getOffset());
 
-  SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, TGA);
-  SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, TGA);
+  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);
 }
@@ -463,65 +614,32 @@ bool PIC16TargetLowering::isRomAddress(const SDValue &Op) {
   // 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);
-  const Type *ValueType = GSDN->getGlobal()->getType();
 
-  if (!isa<PointerType>(ValueType)) {
-    assert(0 && "TGA must be of a PointerType");
-  }
-
-  int AddrSpace = dyn_cast<PointerType>(ValueType)->getAddressSpace();
-  if (AddrSpace == PIC16ISD::ROM_SPACE)
+  if (GSDN->getAddressSpace() == PIC16ISD::ROM_SPACE)
     return true;
 
   // Any other address space return it false
   return false;
 }
 
-// Extract the out flag 
-SDValue PIC16TargetLowering::getOutFlag(SDValue &Op) {
-  SDValue Flag = Op.getValue(Op.getNode()->getNumValues() - 1);
-
-  assert (Flag.getValueType() == MVT::Flag && "Node does not have an out Flag");
 
-  return Flag;
-}
-
-// 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.
-SDValue PIC16TargetLowering::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;
-}
+// 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) {  
   SDNode *N = Op.getNode();
   DebugLoc dl = N->getDebugLoc();
-  MVT NewVT;
-  std::vector<SDValue> Opers;
-  NewVT = getTypeToTransformTo(N->getValueType(0));
-
-  // extract the lo component
-  Opers.push_back(Op);
-  Opers.push_back(DAG.getConstant(0,MVT::i8));
-  Lo = DAG.getNode(ISD::EXTRACT_ELEMENT,dl,NewVT,&Opers[0],Opers.size());
+  MVT NewVT = getTypeToTransformTo(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
-  Opers.clear();
-  Opers.push_back(Op);
-  Opers.push_back(DAG.getConstant(1,MVT::i8));
-  Hi = DAG.getNode(ISD::EXTRACT_ELEMENT,dl,NewVT,&Opers[0],Opers.size());
+  Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NewVT, Op,
+                   DAG.getConstant(1, MVT::i8));
 }
 
 // Legalize FrameIndex into ExternalSymbol and offset.
@@ -531,13 +649,31 @@ PIC16TargetLowering::LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG,
 
   MachineFunction &MF = DAG.getMachineFunction();
   const Function *Func = MF.getFunction();
+  MachineFrameInfo *MFI = MF.getFrameInfo();
   const std::string Name = Func->getName();
 
-  char *tmpName = new char [strlen(Name.c_str()) +  8];
-  sprintf(tmpName, "%s.args", Name.c_str());
-  ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8);
   FrameIndexSDNode *FR = dyn_cast<FrameIndexSDNode>(Op);
-  Offset = FR->getIndex();
+
+  // 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 < ReservedFrameCount) {
+    tmpName = 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 = createESName(PAN::getTempdataLabel(Name));
+    ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8);
+    Offset = GetTmpOffsetForFI(FIndex, MFI->getObjectSize(FIndex));
+  }
 
   return;
 }
@@ -554,9 +690,9 @@ PIC16TargetLowering::LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG,
 //         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) {
+void PIC16TargetLowering::LegalizeAddress(SDValue Ptr, SelectionDAG &DAG, 
+                                          SDValue &Lo, SDValue &Hi,
+                                          unsigned &Offset, DebugLoc dl) {
 
   // Offset, by default, should be 0
   Offset = 0;
@@ -588,14 +724,26 @@ void PIC16TargetLowering:: LegalizeAddress(SDValue Ptr, SelectionDAG &DAG,
     }
   }
 
-  if (Ptr.getOpcode() == ISD::BUILD_PAIR && 
-      Ptr.getOperand(0).getOpcode() == ISD::TargetFrameIndex) {
-
-    int FrameOffset;
-    LegalizeFrameIndex(Ptr.getOperand(0), DAG, Lo, FrameOffset);
-    Hi = DAG.getConstant(1, MVT::i8);
-    Offset += FrameOffset; 
-    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)) {
@@ -615,25 +763,12 @@ void PIC16TargetLowering:: LegalizeAddress(SDValue Ptr, SelectionDAG &DAG,
   GetExpandedParts(Ptr, DAG, Lo, Hi);
 
   // Put the hi and lo parts into FSR.
-  Lo = DAG.getNode(PIC16ISD::MTLO, MVT::i8, Lo);
-  Hi = DAG.getNode(PIC16ISD::MTHI, MVT::i8, Hi);
+  Lo = DAG.getNode(PIC16ISD::MTLO, dl, MVT::i8, Lo);
+  Hi = DAG.getNode(PIC16ISD::MTHI, dl, MVT::i8, Hi);
 
   return;
 }
 
-//SDValue PIC16TargetLowering::ExpandAdd(SDNode *N, SelectionDAG &DAG) {
-  //SDValue OperLeft = N->getOperand(0);
-  //SDValue OperRight = N->getOperand(1);
-
-  //if((OperLeft.getOpcode() == ISD::Constant) ||
-     //(OperRight.getOpcode() == ISD::Constant)) {
-    //return SDValue();
-  //}
-
-  // These case are yet to be handled
-  //return SDValue();
-//}
-
 SDValue PIC16TargetLowering::ExpandLoad(SDNode *N, SelectionDAG &DAG) {
   LoadSDNode *LD = dyn_cast<LoadSDNode>(SDValue(N, 0));
   SDValue Chain = LD->getChain();
@@ -648,7 +783,7 @@ SDValue PIC16TargetLowering::ExpandLoad(SDNode *N, SelectionDAG &DAG) {
 
   // Legalize direct/indirect addresses. This will give the lo and hi parts
   // of the address and the offset.
-  LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, LoadOffset);
+  LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, LoadOffset, dl);
 
   // Load from the pointer (direct address or FSR) 
   VT = N->getValueType(0);
@@ -697,7 +832,8 @@ SDValue PIC16TargetLowering::ExpandLoad(SDNode *N, SelectionDAG &DAG) {
       for (iter=MemBytes; iter<ExtdBytes; ++iter) { 
         PICLoads.push_back(SRA);
       }
-    } else if (ISD::isZEXTLoad(N)) {
+    } 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) { 
@@ -851,12 +987,11 @@ SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op,
   const Function *Func = MF.getFunction();
   const std::string FuncName = Func->getName();
 
-  char *tmpName = new char [strlen(FuncName.c_str()) +  6];
 
   // Put the value on stack.
   // Get a stack slot index and convert to es.
   int FI = MF.getFrameInfo()->CreateStackObject(1, 1);
-  sprintf(tmpName, "%s.tmp", FuncName.c_str());
+  const char *tmpName = createESName(PAN::getTempdataLabel(FuncName));
   SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8);
 
   // Store the value to ES.
@@ -864,30 +999,73 @@ SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op,
                                DAG.getEntryNode(),
                                Op, ES, 
                                DAG.getConstant (1, MVT::i8), // Banksel.
-                               DAG.getConstant (FI, MVT::i8));
+                               DAG.getConstant (GetTmpOffsetForFI(FI, 1), 
+                                                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 (FI, MVT::i8));
+                             DAG.getConstant (GetTmpOffsetForFI(FI, 1), 
+                             MVT::i8));
     
   return Load.getValue(0);
 }
-          
-SDValue
-PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
-                                        SDValue FrameAddress, 
-                                        SDValue InFlag,
-                                        SelectionDAG &DAG) {
+
+SDValue PIC16TargetLowering::
+LowerIndirectCallArguments(SDValue Op, SDValue Chain, SDValue InFlag,
+                           SDValue DataAddr_Lo, SDValue DataAddr_Hi,
+                           SelectionDAG &DAG) {
   CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
   unsigned NumOps = TheCall->getNumArgs();
+  DebugLoc dl = TheCall->getDebugLoc();
+
+  // 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 = TheCall->getNumRetVals();
+  for (unsigned i = 0, ArgOffset = RetVals; i < NumOps; i++) {
+    // Get the arguments
+    Arg = TheCall->getArg(i);
+    
+    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 Op, SDValue Chain, SDValue ArgLabel, 
+                         SDValue InFlag, SelectionDAG &DAG) {
+  CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
+  unsigned NumOps = TheCall->getNumArgs();
+  DebugLoc dl = TheCall->getDebugLoc();
   std::string Name;
   SDValue Arg, StoreAt;
   MVT ArgVT;
   unsigned Size=0;
   unsigned ArgCount=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.
@@ -896,7 +1074,7 @@ PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
   SDValue PtrLo, PtrHi;
   unsigned AddressOffset;
   int StoreOffset = 0;
-  LegalizeAddress(FrameAddress, DAG, PtrLo, PtrHi, AddressOffset);
+  LegalizeAddress(ArgLabel, DAG, PtrLo, PtrHi, AddressOffset, dl);
   SDValue StoreRet;
 
   std::vector<SDValue> Ops;
@@ -904,20 +1082,19 @@ PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
   for (unsigned i=ArgCount, Offset = 0; i<NumOps; i++) {
     // Get the argument
     Arg = TheCall->getArg(i);
-
     StoreOffset = (Offset + AddressOffset);
    
     // Store the argument on frame
 
     Ops.clear();
     Ops.push_back(Chain);
-    Ops.push_back(Arg.getValue(0));
+    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, Tys, &Ops[0], Ops.size());
+    StoreRet = DAG.getNode (PIC16ISD::PIC16StWF, dl, Tys, &Ops[0], Ops.size());
 
     Chain = getChain(StoreRet);
     InFlag = getOutFlag(StoreRet);
@@ -931,11 +1108,40 @@ PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
   return Chain;
 }
 
-SDValue
-PIC16TargetLowering::LowerCallReturn(SDValue Op, SDValue Chain,
-                                     SDValue FrameAddress,
-                                     SDValue InFlag,
-                                     SelectionDAG &DAG) {
+SDValue PIC16TargetLowering::
+LowerIndirectCallReturn (SDValue Op, SDValue Chain, SDValue InFlag,
+                         SDValue DataAddr_Lo, SDValue DataAddr_Hi,
+                         SelectionDAG &DAG) {
+  CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
+  DebugLoc dl = TheCall->getDebugLoc();
+  unsigned RetVals = TheCall->getNumRetVals();
+
+  // If call does not have anything to return
+  // then do nothing and go back.
+  if (RetVals == 0)
+    return Chain;
+
+  // Call has something to return
+  std::vector<SDValue> ResultVals;
+  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);
+    ResultVals.push_back(LoadRet);
+  }
+  ResultVals.push_back(Chain);
+  SDValue Res = DAG.getMergeValues(&ResultVals[0], ResultVals.size(), dl);
+  return Res;
+}
+
+SDValue PIC16TargetLowering::
+LowerDirectCallReturn(SDValue Op, SDValue Chain, SDValue RetLabel,
+                      SDValue InFlag, SelectionDAG &DAG) {
   CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
   DebugLoc dl = TheCall->getDebugLoc();
   // Currently handling primitive types only. They will come in
@@ -953,7 +1159,7 @@ PIC16TargetLowering::LowerCallReturn(SDValue Op, SDValue Chain,
   // Legalize the address before use
   SDValue LdLo, LdHi;
   unsigned LdOffset;
-  LegalizeAddress(FrameAddress, DAG, LdLo, LdHi, LdOffset);
+  LegalizeAddress(RetLabel, DAG, LdLo, LdHi, LdOffset, dl);
 
   SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag);
   SDValue LoadRet;
@@ -978,53 +1184,194 @@ PIC16TargetLowering::LowerCallReturn(SDValue Op, SDValue Chain,
 }
 
 SDValue PIC16TargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) {
- //int NumOps = Op.getNode()->getNumOperands();
+  SDValue Chain = Op.getOperand(0);
+  DebugLoc dl = Op.getDebugLoc();
+
+  if (Op.getNumOperands() == 1)   // return void
+    return Op;
 
- // For default cases LLVM returns the value on the function frame 
- // So let LLVM do this for all the cases other than character
- return Op; 
+  // return should have odd number of operands
+  if ((Op.getNumOperands() % 2) == 0 ) {
+    assert(0 && "Do not know how to return this many arguments!");
+    abort();
+  }
+  
+  // Number of values to return 
+  unsigned NumRet = (Op.getNumOperands() / 2);
+
+  // 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 = createESName(PAN::getFrameLabel(FuncName));
+  SDVTList VTs  = DAG.getVTList (MVT::i8, MVT::Other);
+  SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8);
+  SDValue BS = DAG.getConstant(1, MVT::i8);
+  SDValue RetVal;
+  for(unsigned i=0;i<NumRet; ++i) {
+    RetVal = Op.getNode()->getOperand(2*i + 1);
+    Chain =  DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, RetVal,
+                        ES, BS,
+                        DAG.getConstant (i, MVT::i8));
+      
+  }
+  return DAG.getNode(ISD::RET, dl, MVT::Other, Chain);
 }
 
-SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
+// CALL node may have some operands non-legal to PIC16. Generate new CALL
+// node with all the operands legal.
+// Currently only Callee operand of the CALL node is non-legal. This function
+// legalizes the Callee operand and uses all other operands as are to generate
+// new CALL node.
+
+SDValue PIC16TargetLowering::LegalizeCALL(SDValue Op, SelectionDAG &DAG) {
     CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
     SDValue Chain = TheCall->getChain();
     SDValue Callee = TheCall->getCallee();
     DebugLoc dl = TheCall->getDebugLoc();
     unsigned i =0;
-    if (Callee.getValueType() == MVT::i16 &&
-      Callee.getOpcode() == ISD::BUILD_PAIR) {
-      // It has come from TypeLegalizer for lowering
 
-      Callee = Callee.getOperand(0).getOperand(0);
-
-      std::vector<SDValue> Ops;
-      Ops.push_back(Chain);
-      Ops.push_back(Callee);
+    assert(Callee.getValueType() == MVT::i16 &&
+           "Don't know how to legalize this call node!!!");
+    assert(Callee.getOpcode() == ISD::BUILD_PAIR &&
+           "Don't know how to legalize this call node!!!");
+
+    if (isDirectAddress(Callee)) {
+       // Come here for direct calls
+       Callee = Callee.getOperand(0).getOperand(0);
+    } else {
+      // 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);
+    }
+    std::vector<SDValue> Ops;
+    Ops.push_back(Chain);
+    Ops.push_back(Callee);
 
-      // Add the call arguments and their flags
-      unsigned NumArgs = TheCall->getNumArgs();
-      for(i=0;i<NumArgs;i++) { 
-        Ops.push_back(TheCall->getArg(i));
-        Ops.push_back(TheCall->getArgFlagsVal(i));
-      }
+    // Add the call arguments and their flags
+    unsigned NumArgs = TheCall->getNumArgs();
+    for(i=0;i<NumArgs;i++) {
+       Ops.push_back(TheCall->getArg(i));
+       Ops.push_back(TheCall->getArgFlagsVal(i));
+    }
+    std::vector<MVT> NodeTys;
+    unsigned NumRets = TheCall->getNumRetVals();
+    for(i=0;i<NumRets;i++)
+       NodeTys.push_back(TheCall->getRetValType(i));
 
-      std::vector<MVT> NodeTys;
-      unsigned NumRets = TheCall->getNumRetVals();
-      for(i=0;i<NumRets;i++)
-        NodeTys.push_back(TheCall->getRetValType(i));
+   // Return a Chain as well
+   NodeTys.push_back(MVT::Other);
+   
+   SDVTList VTs = DAG.getVTList(&NodeTys[0], NodeTys.size());
+   // Generate new call with all the operands legal
+   return DAG.getCall(TheCall->getCallingConv(), dl,
+                      TheCall->isVarArg(), TheCall->isTailCall(),
+                      TheCall->isInreg(), VTs, &Ops[0], Ops.size());
+}
 
-      // Return a Chain as well
-      NodeTys.push_back(MVT::Other);
+void PIC16TargetLowering::
+GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain, 
+               SDValue &DataAddr_Lo, SDValue &DataAddr_Hi,
+               SelectionDAG &DAG) {
+   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);
+}
 
-      SDVTList VTs = DAG.getVTList(&NodeTys[0], NodeTys.size());
-      SDValue NewCall = 
-              DAG.getCall(TheCall->getCallingConv(), dl,
-                          TheCall->isVarArg(), TheCall->isTailCall(), 
-                          TheCall->isInreg(), VTs, &Ops[0], Ops.size());
 
-      return NewCall;
+SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
+    CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
+    SDValue Chain = TheCall->getChain();
+    SDValue Callee = TheCall->getCallee();
+    DebugLoc dl = TheCall->getDebugLoc();
+    if (Callee.getValueType() == MVT::i16 &&
+      Callee.getOpcode() == ISD::BUILD_PAIR) {
+          // Control should come here only from TypeLegalizer for lowering
+          
+          // Legalize the non-legal arguments of call and return the
+          // new call with legal arguments.
+          return LegalizeCALL(Op, DAG);
     }
+    // Control should come here from Legalize DAG.
+    // Here all the operands of CALL node should be legal.
     
+    // 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.
+
+    // The flag to track if this is a direct or indirect call.
+    bool IsDirectCall = true;    
+    unsigned RetVals = TheCall->getNumRetVals();
+    unsigned NumArgs = TheCall->getNumArgs();
+
+    SDValue DataAddr_Lo, DataAddr_Hi; 
+    if (Callee.getOpcode() == PIC16ISD::PIC16Connect) { 
+       IsDirectCall = false;    // This is indirect call
+       // 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.
@@ -1032,45 +1379,57 @@ SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
     // 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
-
-    // Considering the GlobalAddressNode case here.
-    if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
-      GlobalValue *GV = G->getGlobal();
-      Callee = DAG.getTargetGlobalAddress(GV, MVT::i8);
-    }
-
-    // Considering the ExternalSymbol case here
-    if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee)) {
-      Callee = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8); 
-    }
-
-    SDValue OperFlag = getOutFlag(Chain); // To manage the data dependency
-
-    std::string Name;
-
-    // Considering GlobalAddress here
-    if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
-       Name = G->getGlobal()->getName();
-
-    // Considering ExternalSymbol here
-    if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee))
-       Name = ES->getSymbol();
-
-    char *argFrame = new char [strlen(Name.c_str()) +  8];
-    sprintf(argFrame, "%s.args", Name.c_str());
-    SDValue ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8);
-
-    char *retName = new char [strlen(Name.c_str()) +  8];
-    sprintf(retName, "%s.retval", Name.c_str());
-    SDValue RetLabel = DAG.getTargetExternalSymbol(retName, MVT::i8);
+    SDValue ArgLabel, RetLabel;
+    if (IsDirectCall) { 
+       // Considering the GlobalAddressNode case here.
+       if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+          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 = createESName(PAN::getArgsLabel(Name));
+       ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8);
+
+       // Label for reading return value
+       const char *retName = 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 = LowerCallArguments(Op, Chain, ArgLabel, OperFlag, DAG);
-    Chain = getChain(CallArgs);
-    OperFlag = getOutFlag(CallArgs);
+    SDValue CallArgs;
+    if (IsDirectCall) {
+      CallArgs = LowerDirectCallArguments(Op, Chain, ArgLabel, OperFlag, DAG);
+      Chain = getChain(CallArgs);
+      OperFlag = getOutFlag(CallArgs);
+    } else {
+      CallArgs = LowerIndirectCallArguments(Op, Chain, OperFlag, DataAddr_Lo, 
+                                            DataAddr_Hi, 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,
@@ -1087,7 +1446,11 @@ SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
     OperFlag = getOutFlag(SeqEnd);
 
     // Lower the return value reading after the call.
-    return LowerCallReturn(Op, Chain, RetLabel, OperFlag, DAG);
+    if (IsDirectCall)
+      return LowerDirectCallReturn(Op, Chain, RetLabel, OperFlag, DAG);
+    else
+      return LowerIndirectCallReturn(Op, Chain, OperFlag, DataAddr_Lo,
+                                     DataAddr_Hi, DAG);
 }
 
 bool PIC16TargetLowering::isDirectLoad(const SDValue Op) {
@@ -1098,12 +1461,19 @@ bool PIC16TargetLowering::isDirectLoad(const SDValue Op) {
   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) {
-  // Return false if one of the operands is already a direct
-  // load and that operand has only one use.
+  // 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())
       return false;
@@ -1119,10 +1489,14 @@ bool PIC16TargetLowering::NeedToConvertToMemOp(SDValue Op, unsigned &MemOp) {
   return true;
 }  
 
-SDValue PIC16TargetLowering:: LowerBinOp(SDValue Op, SelectionDAG &DAG) {
+// LowerBinOp - Lower a commutative binary operation that does not
+// affect status flag carry.
+SDValue PIC16TargetLowering::LowerBinOp(SDValue Op, SelectionDAG &DAG) {
   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)) {
     // Put one value on stack.
@@ -1136,7 +1510,9 @@ SDValue PIC16TargetLowering:: LowerBinOp(SDValue Op, SelectionDAG &DAG) {
   }
 }
 
-SDValue PIC16TargetLowering:: LowerADD(SDValue Op, SelectionDAG &DAG) {
+// LowerADD - Lower all types of ADD operations including the ones
+// that affects carry.
+SDValue PIC16TargetLowering::LowerADD(SDValue Op, SelectionDAG &DAG) {
   // We should have handled larger operands in type legalizer itself.
   assert (Op.getValueType() == MVT::i8 && "illegal add to lower");
   DebugLoc dl = Op.getDebugLoc();
@@ -1145,21 +1521,24 @@ SDValue PIC16TargetLowering:: LowerADD(SDValue Op, SelectionDAG &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));
-    else
+    // 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 if (Op.getOpcode() == ISD::ADD) {
+  else
     return Op;
-  }
-  else {
-    return SDValue();
-  }
 }
 
 SDValue PIC16TargetLowering::LowerSUB(SDValue Op, SelectionDAG &DAG) {
@@ -1170,7 +1549,7 @@ SDValue PIC16TargetLowering::LowerSUB(SDValue Op, SelectionDAG &DAG) {
   // Nothing to do if the first operand is already a direct load and it has
   // only one use.
   if (isDirectLoad(Op.getOperand(0)) && Op.getOperand(0).hasOneUse())
-    return SDValue();
+    return Op;
 
   // Put first operand on stack.
   SDValue NewVal = ConvertToMemOperand (Op.getOperand(0), DAG, dl);
@@ -1183,29 +1562,62 @@ SDValue PIC16TargetLowering::LowerSUB(SDValue Op, SelectionDAG &DAG) {
     return DAG.getNode(Op.getOpcode(), dl, Tys, NewVal, Op.getOperand(1));
 }
 
-// LowerFORMAL_ARGUMENTS - In Lowering FORMAL ARGUMENTS - MERGE_VALUES nodes
-// is returned. MERGE_VALUES nodes number of operands and number of values are
-// equal. Therefore to construct MERGE_VALUE node, UNDEF nodes equal to the
-// number of arguments of function have been created.
+void PIC16TargetLowering::InitReservedFrameCount(const Function *F) {
+  unsigned NumArgs = F->arg_size();
+
+  bool isVoidFunc = (F->getReturnType()->getTypeID() == Type::VoidTyID);
+
+  if (isVoidFunc)
+    ReservedFrameCount = NumArgs;
+  else
+    ReservedFrameCount = NumArgs + 1;
+}
+
+// LowerFORMAL_ARGUMENTS - 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:: LowerFORMAL_ARGUMENTS(SDValue Op, 
-                                                    SelectionDAG &DAG) {
+SDValue PIC16TargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op, 
+                                                   SelectionDAG &DAG) {
   SmallVector<SDValue, 8> ArgValues;
-  unsigned NumArgs = Op.getNumOperands() - 3;
+  unsigned NumArgVals = Op.getNode()->getNumValues() - 1;
+  DebugLoc dl = Op.getDebugLoc();
+  SDValue Chain = Op.getOperand(0);    // Formal arguments' chain
+
+
+  // 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();
+  // Initialize the ReserveFrameCount
+  InitReservedFrameCount(F);
 
-  // Creating UNDEF nodes to meet the requirement of MERGE_VALUES node.
-  for(unsigned i = 0 ; i<NumArgs ; i++) {
-    SDValue TempNode = DAG.getNode(ISD::UNDEF, Op.getNode()->getValueType(i));
-    ArgValues.push_back(TempNode);
+  // Create the <fname>.args external symbol.
+  const char *tmpName = 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);
+    ArgValues.push_back(PICLoad);
   }
 
+  // Return a MERGE_VALUE node.
   ArgValues.push_back(Op.getOperand(0));
-  return DAG.getNode(ISD::MERGE_VALUES, Op.getNode()->getVTList(), 
-                     &ArgValues[0],
-                     ArgValues.size()).getValue(Op.getResNo());
+  return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), 
+                     &ArgValues[0], ArgValues.size()).getValue(Op.getResNo());
 }
 
-// Perform DAGCombine of PIC16Load 
+// Perform DAGCombine of PIC16Load.
+// FIXME - Need a more elaborate comment here.
 SDValue PIC16TargetLowering::
 PerformPIC16LoadCombine(SDNode *N, DAGCombinerInfo &DCI) const {
   SelectionDAG &DAG = DCI.DAG;
@@ -1216,11 +1628,32 @@ PerformPIC16LoadCombine(SDNode *N, DAGCombinerInfo &DCI) const {
   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 PIC16ISD::PIC16Load:
+  case ISD::STORE:   
+   return PerformStoreCombine(N, DCI); 
+  case PIC16ISD::PIC16Load:   
     return PerformPIC16LoadCombine(N, DCI);
   }
   return SDValue();
@@ -1236,8 +1669,8 @@ static PIC16CC::CondCodes IntCCToPIC16CC(ISD::CondCode CC) {
   case ISD::SETLT:  return PIC16CC::LT;
   case ISD::SETLE:  return PIC16CC::LE;
   case ISD::SETULT: return PIC16CC::ULT;
-  case ISD::SETULE: return PIC16CC::LE;
-  case ISD::SETUGE: return PIC16CC::GE;
+  case ISD::SETULE: return PIC16CC::ULE;
+  case ISD::SETUGE: return PIC16CC::UGE;
   case ISD::SETUGT: return PIC16CC::UGT;
   }
 }
@@ -1357,9 +1790,10 @@ SDValue PIC16TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) {
 
 MachineBasicBlock *
 PIC16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
-                                                 MachineBasicBlock *BB) {
+                                                 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
@@ -1378,7 +1812,7 @@ PIC16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
   MachineFunction *F = BB->getParent();
   MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
   MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
-  BuildMI(BB, TII.get(PIC16::pic16brcond)).addMBB(sinkMBB).addImm(CC);
+  BuildMI(BB, dl, TII.get(PIC16::pic16brcond)).addMBB(sinkMBB).addImm(CC);
   F->insert(It, copy0MBB);
   F->insert(It, sinkMBB);
 
@@ -1401,7 +1835,7 @@ PIC16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
   //   %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
   //  ...
   BB = sinkMBB;
-  BuildMI(BB, TII.get(PIC16::PHI), MI->getOperand(0).getReg())
+  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);
 
@@ -1432,4 +1866,3 @@ SDValue PIC16TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) {
                      Cmp.getValue(1));
 }
 
-