mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108991 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			2001 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2001 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| //                     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();
 | |
| }
 | |
| 
 | |
| std::pair<const TargetRegisterClass*, uint8_t>
 | |
| PIC16TargetLowering::findRepresentativeClass(EVT VT) const {
 | |
|   switch (VT.getSimpleVT().SimpleTy) {
 | |
|   default:
 | |
|     return TargetLowering::findRepresentativeClass(VT);
 | |
|   case MVT::i16:
 | |
|     return std::make_pair(PIC16::FSR16RegisterClass, 1);
 | |
|   }
 | |
| }
 | |
| 
 | |
| // 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(), N->getDebugLoc(),
 | |
|                                            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<SDValue> &OutVals,
 | |
|                            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 = OutVals[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 ArgLabel, SDValue Chain, SDValue InFlag,
 | |
|                          const SmallVectorImpl<ISD::OutputArg> &Outs,
 | |
|                          const SmallVectorImpl<SDValue> &OutVals,
 | |
|                          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 = OutVals[i];
 | |
|     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,
 | |
|                                  const SmallVectorImpl<SDValue> &OutVals,
 | |
|                                  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 = OutVals[i];
 | |
|     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<SDValue> &OutVals,
 | |
|                                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, dl, 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, OutVals, dl, DAG);
 | |
|       Chain = getChain(CallArgs);
 | |
|       OperFlag = getOutFlag(CallArgs);
 | |
|     } else {
 | |
|       CallArgs = LowerIndirectCallArguments(Chain, OperFlag, DataAddr_Lo,
 | |
|                                             DataAddr_Hi, Outs, OutVals, 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)->isNullValue() &&
 | |
|       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))->isOne() &&
 | |
|       cast<ConstantSDNode>(LHS.getOperand(1))->isNullValue()) {
 | |
|     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);
 | |
| 
 | |
|   // Transfer the remainder of BB and its successor edges to sinkMBB.
 | |
|   sinkMBB->splice(sinkMBB->begin(), BB,
 | |
|                   llvm::next(MachineBasicBlock::iterator(MI)),
 | |
|                   BB->end());
 | |
|   sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
 | |
| 
 | |
|   // 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, BB->begin(), dl,
 | |
|           TII.get(PIC16::PHI), MI->getOperand(0).getReg())
 | |
|     .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB)
 | |
|     .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB);
 | |
| 
 | |
|   MI->eraseFromParent();   // 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));
 | |
| }
 | |
| 
 |