//===-- PIC16ISelLowering.cpp - PIC16 DAG Lowering Implementation ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the interfaces that PIC16 uses to lower LLVM code into a // selection DAG. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "pic16-lower" #include "PIC16ISelLowering.h" #include "PIC16TargetMachine.h" #include "llvm/DerivedTypes.h" #include "llvm/GlobalValue.h" #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include using namespace llvm; // PIC16TargetLowering Constructor. PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM) : TargetLowering(TM) { Subtarget = &TM.getSubtarget(); addRegisterClass(MVT::i8, PIC16::GPRRegisterClass); setShiftAmountType(MVT::i8); setShiftAmountFlavor(Extend); setOperationAction(ISD::GlobalAddress, 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::ADDE, MVT::i8, Custom); setOperationAction(ISD::ADDC, MVT::i8, Custom); setOperationAction(ISD::SUBE, MVT::i8, Custom); setOperationAction(ISD::SUBC, MVT::i8, Custom); setOperationAction(ISD::ADD, MVT::i8, Legal); 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::SHL, MVT::i16, Custom); setOperationAction(ISD::SHL, MVT::i32, Custom); //setOperationAction(ISD::TRUNCATE, MVT::i16, Custom); setTruncStoreAction(MVT::i16, MVT::i8, Custom); // Now deduce the information based on the above mentioned // actions computeRegisterProperties(); } 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::Banksel: return "PIC16ISD::Banksel"; case PIC16ISD::PIC16Load: return "PIC16ISD::PIC16Load"; case PIC16ISD::PIC16Store: return "PIC16ISD::PIC16Store"; 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::Dummy: return "PIC16ISD::Dummy"; } } void PIC16TargetLowering::ReplaceNodeResults(SDNode *N, SmallVectorImpl&Results, SelectionDAG &DAG) { switch (N->getOpcode()) { case ISD::GlobalAddress: Results.push_back(ExpandGlobalAddress(N, DAG)); return; case ISD::STORE: Results.push_back(ExpandStore(N, DAG)); return; case ISD::LOAD: Results.push_back(ExpandLoad(N, DAG)); return; case ISD::ADD: // return ExpandAdd(N, DAG); return; case ISD::SHL: { SDValue Res = ExpandShift(N, DAG); if (Res.getNode()) Results.push_back(Res); return; } default: assert (0 && "not implemented"); return; } } SDValue PIC16TargetLowering::ExpandStore(SDNode *N, SelectionDAG &DAG) { StoreSDNode *St = cast(N); SDValue Chain = St->getChain(); SDValue Src = St->getValue(); SDValue Ptr = St->getBasePtr(); MVT ValueType = Src.getValueType(); unsigned StoreOffset = 0; SDValue PtrLo, PtrHi; LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, StoreOffset); if (ValueType == MVT::i8) { return DAG.getNode (PIC16ISD::PIC16Store, MVT::Other, Chain, Src, PtrLo, PtrHi, DAG.getConstant (0, 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; if (Chain.getOpcode() == ISD::TokenFactor) { ChainLo = Chain.getOperand(0); ChainHi = Chain.getOperand(1); } SDValue Store1 = DAG.getNode(PIC16ISD::PIC16Store, MVT::Other, ChainLo, SrcLo, PtrLo, PtrHi, DAG.getConstant (0 + StoreOffset, MVT::i8)); SDValue Store2 = DAG.getNode(PIC16ISD::PIC16Store, MVT::Other, ChainHi, SrcHi, PtrLo, PtrHi, DAG.getConstant (1 + StoreOffset, MVT::i8)); return DAG.getNode(ISD::TokenFactor, 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; if (Chain.getOpcode() == ISD::TokenFactor) { ChainLo = Chain.getOperand(0); ChainHi = Chain.getOperand(1); } SDValue ChainLo1 = ChainLo, ChainLo2 = ChainLo, ChainHi1 = ChainHi, ChainHi2 = ChainHi; if (ChainLo.getOpcode() == ISD::TokenFactor) { ChainLo1 = ChainLo.getOperand(0); ChainLo2 = ChainLo.getOperand(1); } if (ChainHi.getOpcode() == ISD::TokenFactor) { ChainHi1 = ChainHi.getOperand(0); ChainHi2 = ChainHi.getOperand(1); } SDValue Store1 = DAG.getNode(PIC16ISD::PIC16Store, MVT::Other, ChainLo1, SrcLo1, PtrLo, PtrHi, DAG.getConstant (0 + StoreOffset, MVT::i8)); SDValue Store2 = DAG.getNode(PIC16ISD::PIC16Store, MVT::Other, ChainLo2, SrcLo2, PtrLo, PtrHi, DAG.getConstant (1 + StoreOffset, MVT::i8)); SDValue Store3 = DAG.getNode(PIC16ISD::PIC16Store, MVT::Other, ChainHi1, SrcHi1, PtrLo, PtrHi, DAG.getConstant (2 + StoreOffset, MVT::i8)); SDValue Store4 = DAG.getNode(PIC16ISD::PIC16Store, MVT::Other, ChainHi2, SrcHi2, PtrLo, PtrHi, DAG.getConstant (3 + StoreOffset, MVT::i8)); SDValue RetLo = DAG.getNode(ISD::TokenFactor, MVT::Other, getChain(Store1), getChain(Store2)); SDValue RetHi = DAG.getNode(ISD::TokenFactor, MVT::Other, getChain(Store3), getChain(Store4)); return DAG.getNode(ISD::TokenFactor, MVT::Other, RetLo, RetHi); } else { assert (0 && "value type not supported"); return SDValue(); } } // ExpandGlobalAddress - SDValue PIC16TargetLowering::ExpandGlobalAddress(SDNode *N, SelectionDAG &DAG) { GlobalAddressSDNode *G = dyn_cast(SDValue(N, 0)); SDValue TGA = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i8, G->getOffset()); SDValue Lo = DAG.getNode(PIC16ISD::Lo, MVT::i8, TGA); SDValue Hi = DAG.getNode(PIC16ISD::Hi, MVT::i8, TGA); SDValue BP = DAG.getNode(ISD::BUILD_PAIR, MVT::i16, Lo, Hi); return BP; } bool PIC16TargetLowering::isDirectAddress(const SDValue &Op) { 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) { // 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(TGA); const Type *ValueType = GSDN->getGlobal()->getType(); if (!isa(ValueType)) { assert(0 && "TGA must be of a PointerType"); } int AddrSpace = dyn_cast(ValueType)->getAddressSpace(); if (AddrSpace == PIC16ISD::ROM_SPACE) return true; // Any other address space return it false return false; } // 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); // 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; } void PIC16TargetLowering::GetExpandedParts(SDValue Op, SelectionDAG &DAG, SDValue &Lo, SDValue &Hi) { SDNode *N = Op.getNode(); unsigned NumValues = N->getNumValues(); std::vector VTs; MVT NewVT; std::vector Opers; // EXTRACT_ELEMENT should have same number and type of values that the // node replacing the EXTRACT_ELEMENT should have. (i.e. extracted element) // Some nodes such as LOAD and PIC16Load have more than one values. In such // cases EXTRACT_ELEMENT should have more than one values. Therefore creating // vector of Values for EXTRACT_ELEMENT. This list will have same number of // values as the extracted element will have. for (unsigned i=0;i < NumValues; ++i) { NewVT = getTypeToTransformTo(N->getValueType(i)); VTs.push_back(NewVT); } // extract the lo component Opers.push_back(Op); Opers.push_back(DAG.getConstant(0,MVT::i8)); Lo = DAG.getNode(ISD::EXTRACT_ELEMENT,VTs,&Opers[0],Opers.size()); // extract the hi component Opers.clear(); Opers.push_back(Op); Opers.push_back(DAG.getConstant(1,MVT::i8)); Hi = DAG.getNode(ISD::EXTRACT_ELEMENT,VTs,&Opers[0],Opers.size()); } // 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) { // 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) { Offset = dyn_cast(OperLeft)->getZExtValue(); Ptr = OperRight; } else { Ptr = OperLeft; Offset = dyn_cast(OperRight)->getZExtValue(); } } 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, MVT::i8, Lo); Hi = DAG.getNode(PIC16ISD::MTHI, MVT::i8, Hi); return; } //SDNode *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 NULL; // } // // // These case are yet to be handled // return NULL; //} SDValue PIC16TargetLowering::ExpandLoad(SDNode *N, SelectionDAG &DAG) { LoadSDNode *LD = dyn_cast(SDValue(N, 0)); SDValue Chain = LD->getChain(); SDValue Ptr = LD->getBasePtr(); SDValue Load, Offset; SDVTList Tys; MVT 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); // Load from the pointer (direct address or FSR) VT = N->getValueType(0); unsigned NumLoads = VT.getSizeInBits() / 8; std::vector PICLoads; unsigned iter; MVT MemVT = LD->getMemoryVT(); if(ISD::isNON_EXTLoad(N)) { for (iter=0; itergetMemoryVT(); unsigned MemBytes = MemVT.getSizeInBits() / 8; 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; itergetOperand(0); SDValue Amt = N->getOperand(1); SDValue BCF, BCFInput; SDVTList Tys; SDValue ShfCom; // Shift Component - Lo component should be shifted SDValue RotCom; // Rotate Component- Hi component should be rotated PIC16ISD::NodeType ShfNode = PIC16ISD::Dummy, RotNode = PIC16ISD::Dummy; // Currently handling Constant shift only if (Amt.getOpcode() != ISD::Constant) return SDValue(); // Following code considers 16 bit left-shift only if (N->getValueType(0) != MVT::i16) return SDValue(); if (N->getOpcode() == ISD::SHL) { ShfNode = PIC16ISD::LSLF; RotNode = PIC16ISD::RLF; } else if (N->getOpcode() == ISD::SRL) { ShfNode = PIC16ISD::LRLF; RotNode = PIC16ISD::RRF; } unsigned ShiftAmt = dyn_cast(Amt)->getZExtValue(); SDValue StatusReg = DAG.getRegister(PIC16::STATUS, MVT::i8); // 0th Bit in StatusReg is CarryBit SDValue CarryBit= DAG.getConstant(0, MVT::i8); GetExpandedParts(Value, DAG, ShfCom, RotCom); BCFInput = DAG.getNode(PIC16ISD::Dummy, MVT::Flag); Tys = DAG.getVTList(MVT::i8, MVT::Flag); for (unsigned i=0;igetValueType(0), ShfCom, RotCom); } SDValue PIC16TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { switch (Op.getOpcode()) { case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); case ISD::ADDC: return LowerADDC(Op, DAG); case ISD::ADDE: return LowerADDE(Op, DAG); case ISD::SUBE: return LowerSUBE(Op, DAG); case ISD::SUBC: return LowerSUBC(Op, DAG); case ISD::LOAD: return ExpandLoad(Op.getNode(), DAG); case ISD::STORE: return ExpandStore(Op.getNode(), DAG); case ISD::SHL: return ExpandShift(Op.getNode(), DAG); case ISD::OR: case ISD::AND: case ISD::XOR: return LowerBinOp(Op, DAG); } return SDValue(); } SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op, SelectionDAG &DAG) { 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(); 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()); SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); // Store the value to ES. SDValue Store = DAG.getNode (PIC16ISD::PIC16Store, MVT::Other, DAG.getEntryNode(), Op, ES, DAG.getConstant (1, MVT::i8), // Banksel. DAG.getConstant (FI, MVT::i8)); // Load the value from ES. SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other); SDValue Load = DAG.getNode(PIC16ISD::PIC16Load, Tys, Store, ES, DAG.getConstant (1, MVT::i8), DAG.getConstant (FI, MVT::i8)); return Load.getValue(0); } SDValue PIC16TargetLowering:: LowerBinOp(SDValue Op, SelectionDAG &DAG) { // We should have handled larger operands in type legalizer itself. assert (Op.getValueType() == MVT::i8 && "illegal Op to lower"); // Return the original Op if the one of the operands is already a load. if (Op.getOperand(0).getOpcode() == PIC16ISD::PIC16Load || Op.getOperand(1).getOpcode() == PIC16ISD::PIC16Load) return Op; // Put one value on stack. SDValue NewVal = ConvertToMemOperand (Op.getOperand(1), DAG); return DAG.getNode(Op.getOpcode(), MVT::i8, Op.getOperand(0), NewVal); } SDValue PIC16TargetLowering:: LowerADDC(SDValue Op, SelectionDAG &DAG) { // We should have handled larger operands in type legalizer itself. assert (Op.getValueType() == MVT::i8 && "illegal addc to lower"); // Nothing to do if the one of the operands is already a load. if (Op.getOperand(0).getOpcode() == PIC16ISD::PIC16Load || Op.getOperand(1).getOpcode() == PIC16ISD::PIC16Load) return SDValue(); // Put one value on stack. SDValue NewVal = ConvertToMemOperand (Op.getOperand(1), DAG); SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); return DAG.getNode(ISD::ADDC, Tys, Op.getOperand(0), NewVal); } SDValue PIC16TargetLowering:: LowerADDE(SDValue Op, SelectionDAG &DAG) { // We should have handled larger operands in type legalizer itself. assert (Op.getValueType() == MVT::i8 && "illegal adde to lower"); // Nothing to do if the one of the operands is already a load. if (Op.getOperand(0).getOpcode() == PIC16ISD::PIC16Load || Op.getOperand(1).getOpcode() == PIC16ISD::PIC16Load) return SDValue(); // Put one value on stack. SDValue NewVal = ConvertToMemOperand (Op.getOperand(1), DAG); SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); return DAG.getNode(ISD::ADDE, Tys, Op.getOperand(0), NewVal, Op.getOperand(2)); } SDValue PIC16TargetLowering:: LowerSUBC(SDValue Op, SelectionDAG &DAG) { // We should have handled larger operands in type legalizer itself. assert (Op.getValueType() == MVT::i8 && "illegal subc to lower"); // Nothing to do if the first operand is already a load. if (Op.getOperand(0).getOpcode() == PIC16ISD::PIC16Load) return SDValue(); // Put first operand on stack. SDValue NewVal = ConvertToMemOperand (Op.getOperand(0), DAG); SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); return DAG.getNode(ISD::SUBC, Tys, NewVal, Op.getOperand(1)); } SDValue PIC16TargetLowering:: LowerSUBE(SDValue Op, SelectionDAG &DAG) { // We should have handled larger operands in type legalizer itself. assert (Op.getValueType() == MVT::i8 && "illegal sube to lower"); // Nothing to do if the first operand is already a load. if (Op.getOperand(0).getOpcode() == PIC16ISD::PIC16Load) return SDValue(); // Put first operand on stack. SDValue NewVal = ConvertToMemOperand (Op.getOperand(0), DAG); SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); return DAG.getNode(ISD::SUBE, Tys, NewVal, Op.getOperand(1), Op.getOperand(2)); } // 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. SDValue PIC16TargetLowering:: LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG) { SmallVector ArgValues; unsigned NumArgs = Op.getNumOperands() - 3; // Creating UNDEF nodes to meet the requirement of MERGE_VALUES node. for(unsigned i = 0 ; igetValueType(i)); ArgValues.push_back(TempNode); } ArgValues.push_back(Op.getOperand(0)); return DAG.getNode(ISD::MERGE_VALUES, Op.getNode()->getVTList(), &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); } // Perform DAGCombine of PIC16Load 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(); } SDValue PIC16TargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { switch (N->getOpcode()) { case PIC16ISD::PIC16Load: return PerformPIC16LoadCombine(N, DCI); } return SDValue(); }