Handle indirect function calls.

Every function has the address of its frame in the beginning of code section.
The frame address is retrieved and used to pass arguments.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@68597 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjiv Gupta 2009-04-08 05:38:48 +00:00
parent bd6de0a2b3
commit 7836fc129a
5 changed files with 346 additions and 89 deletions

View File

@ -113,6 +113,10 @@ bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
SectionFlags::Code);
O << "\n";
SwitchToSection (fCodeSection);
O << CurrentFnName << ":\n";
O << " retlw low(" << CurrentFnName << ".frame)\n";
O << " retlw high(" << CurrentFnName << ".frame)\n";
// Print out code for the function.
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
@ -122,8 +126,6 @@ bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
printBasicBlockLabel(I, true);
O << '\n';
}
else
O << CurrentFnName << ":\n";
CurBank = "";
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {

View File

@ -255,6 +255,8 @@ const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const {
case PIC16ISD::Hi: return "PIC16ISD::Hi";
case PIC16ISD::MTLO: return "PIC16ISD::MTLO";
case PIC16ISD::MTHI: return "PIC16ISD::MTHI";
case PIC16ISD::MTPCLATH: return "PIC16ISD::MTPCLATH";
case PIC16ISD::PIC16Connect: return "PIC16ISD::PIC16Connect";
case PIC16ISD::Banksel: return "PIC16ISD::Banksel";
case PIC16ISD::PIC16Load: return "PIC16ISD::PIC16Load";
case PIC16ISD::PIC16LdArg: return "PIC16ISD::PIC16LdArg";
@ -267,6 +269,7 @@ const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const {
case PIC16ISD::RLF: return "PIC16ISD::RLF";
case PIC16ISD::RRF: return "PIC16ISD::RRF";
case PIC16ISD::CALL: return "PIC16ISD::CALL";
case PIC16ISD::CALLW: return "PIC16ISD::CALLW";
case PIC16ISD::SUBCC: return "PIC16ISD::SUBCC";
case PIC16ISD::SELECT_ICC: return "PIC16ISD::SELECT_ICC";
case PIC16ISD::BRCOND: return "PIC16ISD::BRCOND";
@ -872,12 +875,44 @@ SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op,
return Load.getValue(0);
}
SDValue PIC16TargetLowering::
LowerIndirectCallArguments(SDValue Op, SDValue Chain, SDValue InFlag,
SDValue DataAddr_Lo, SDValue DataAddr_Hi,
SelectionDAG &DAG) {
CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
unsigned NumOps = TheCall->getNumArgs();
DebugLoc dl = TheCall->getDebugLoc();
// If call has no arguments then do nothing and return.
if (NumOps == 0)
return Chain;
std::vector<SDValue> Ops;
SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag);
SDValue Arg, StoreRet;
for (unsigned i=0; i<NumOps; i++) {
// Get the arguments
Arg = TheCall->getArg(i);
Ops.clear();
Ops.push_back(Chain);
Ops.push_back(Arg);
Ops.push_back(DataAddr_Lo);
Ops.push_back(DataAddr_Hi);
Ops.push_back(DAG.getConstant(i, MVT::i8));
Ops.push_back(InFlag);
StoreRet = DAG.getNode (PIC16ISD::PIC16StWF, dl, Tys, &Ops[0], Ops.size());
Chain = getChain(StoreRet);
InFlag = getOutFlag(StoreRet);
}
return Chain;
}
SDValue
PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
SDValue FrameAddress,
SDValue InFlag,
SelectionDAG &DAG) {
SDValue PIC16TargetLowering::
LowerDirectCallArguments(SDValue Op, SDValue Chain, SDValue FrameAddress,
SDValue InFlag, SelectionDAG &DAG) {
CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
unsigned NumOps = TheCall->getNumArgs();
DebugLoc dl = TheCall->getDebugLoc();
@ -887,6 +922,9 @@ PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
unsigned Size=0;
unsigned ArgCount=0;
// If call has no arguments then do nothing and return.
if (NumOps == 0)
return Chain;
// FIXME: This portion of code currently assumes only
// primitive types being passed as arguments.
@ -930,11 +968,40 @@ PIC16TargetLowering::LowerCallArguments(SDValue Op, SDValue Chain,
return Chain;
}
SDValue
PIC16TargetLowering::LowerCallReturn(SDValue Op, SDValue Chain,
SDValue FrameAddress,
SDValue InFlag,
SelectionDAG &DAG) {
SDValue PIC16TargetLowering::
LowerIndirectCallReturn (SDValue Op, SDValue Chain, SDValue InFlag,
SDValue DataAddr_Lo, SDValue DataAddr_Hi,
SelectionDAG &DAG) {
CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
DebugLoc dl = TheCall->getDebugLoc();
unsigned RetVals = TheCall->getNumRetVals();
// If call does not have anything to return
// then do nothing and go back.
if (RetVals == 0)
return Chain;
// Call has something to return
std::vector<SDValue> ResultVals;
SDValue LoadRet;
SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag);
for(unsigned i=0;i<RetVals;i++) {
LoadRet = DAG.getNode(PIC16ISD::PIC16LdWF, dl, Tys, Chain, DataAddr_Lo,
DataAddr_Hi, DAG.getConstant(i, MVT::i8),
InFlag);
InFlag = getOutFlag(LoadRet);
Chain = getChain(LoadRet);
ResultVals.push_back(LoadRet);
}
ResultVals.push_back(Chain);
SDValue Res = DAG.getMergeValues(&ResultVals[0], ResultVals.size(), dl);
return Res;
}
SDValue PIC16TargetLowering::
LowerDirectCallReturn(SDValue Op, SDValue Chain, SDValue FrameAddress,
SDValue InFlag, SelectionDAG &DAG) {
CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
DebugLoc dl = TheCall->getDebugLoc();
// Currently handling primitive types only. They will come in
@ -1014,46 +1081,147 @@ SDValue PIC16TargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) {
return DAG.getNode(ISD::RET, dl, MVT::Other, Chain);
}
SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
// CALL node may have some operands non-legal to PIC16. Generate new CALL
// node with all the operands legal.
// Currently only Callee operand of the CALL node is non-legal. This function
// legalizes the Callee operand and uses all other operands as are to generate
// new CALL node.
SDValue PIC16TargetLowering::LegalizeCALL(SDValue Op, SelectionDAG &DAG) {
CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
SDValue Chain = TheCall->getChain();
SDValue Callee = TheCall->getCallee();
DebugLoc dl = TheCall->getDebugLoc();
unsigned i =0;
assert(Callee.getValueType() == MVT::i16 &&
"Don't know how to legalize this call node!!!");
assert(Callee.getOpcode() == ISD::BUILD_PAIR &&
"Don't know how to legalize this call node!!!");
if (isDirectAddress(Callee)) {
// Come here for direct calls
Callee = Callee.getOperand(0).getOperand(0);
} else {
// Come here for indirect calls
SDValue Lo, Hi;
// Indirect addresses. Get the hi and lo parts of ptr.
GetExpandedParts(Callee, DAG, Lo, Hi);
// Connect Lo and Hi parts of the callee with the PIC16Connect
Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Lo, Hi);
}
std::vector<SDValue> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
// Add the call arguments and their flags
unsigned NumArgs = TheCall->getNumArgs();
for(i=0;i<NumArgs;i++) {
Ops.push_back(TheCall->getArg(i));
Ops.push_back(TheCall->getArgFlagsVal(i));
}
std::vector<MVT> NodeTys;
unsigned NumRets = TheCall->getNumRetVals();
for(i=0;i<NumRets;i++)
NodeTys.push_back(TheCall->getRetValType(i));
// Return a Chain as well
NodeTys.push_back(MVT::Other);
SDVTList VTs = DAG.getVTList(&NodeTys[0], NodeTys.size());
// Generate new call with all the operands legal
return DAG.getCall(TheCall->getCallingConv(), dl,
TheCall->isVarArg(), TheCall->isTailCall(),
TheCall->isInreg(), VTs, &Ops[0], Ops.size());
}
void PIC16TargetLowering::
GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain,
SDValue &DataAddr_Lo, SDValue &DataAddr_Hi,
SelectionDAG &DAG) {
assert (Callee.getOpcode() == PIC16ISD::PIC16Connect
&& "Don't know what to do of such callee!!");
SDValue ZeroOperand = DAG.getConstant(0, MVT::i8);
SDValue SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand);
Chain = getChain(SeqStart);
SDValue OperFlag = getOutFlag(SeqStart); // To manage the data dependency
// Get the Lo and Hi part of code address
SDValue Lo = Callee.getOperand(0);
SDValue Hi = Callee.getOperand(1);
SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag);
Hi = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, Hi);
// Use the Lo part as is and make CALLW
Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Lo, Hi);
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
// Add 1 to Lo part for the second code word.
Lo = DAG.getNode(ISD::ADD, dl, MVT::i8, Lo, DAG.getConstant(1, MVT::i8));
// Use new Lo to make another CALLW
Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Lo, Hi);
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 Op, SelectionDAG &DAG) {
CallSDNode *TheCall = dyn_cast<CallSDNode>(Op);
SDValue Chain = TheCall->getChain();
SDValue Callee = TheCall->getCallee();
DebugLoc dl = TheCall->getDebugLoc();
if (Callee.getValueType() == MVT::i16 &&
Callee.getOpcode() == ISD::BUILD_PAIR) {
// It has come from TypeLegalizer for lowering
Callee = Callee.getOperand(0).getOperand(0);
std::vector<SDValue> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
// Add the call arguments and their flags
unsigned NumArgs = TheCall->getNumArgs();
for(i=0;i<NumArgs;i++) {
Ops.push_back(TheCall->getArg(i));
Ops.push_back(TheCall->getArgFlagsVal(i));
}
std::vector<MVT> NodeTys;
unsigned NumRets = TheCall->getNumRetVals();
for(i=0;i<NumRets;i++)
NodeTys.push_back(TheCall->getRetValType(i));
// Return a Chain as well
NodeTys.push_back(MVT::Other);
SDVTList VTs = DAG.getVTList(&NodeTys[0], NodeTys.size());
SDValue NewCall =
DAG.getCall(TheCall->getCallingConv(), dl,
TheCall->isVarArg(), TheCall->isTailCall(),
TheCall->isInreg(), VTs, &Ops[0], Ops.size());
return NewCall;
// Control should come here only from TypeLegalizer for lowering
// Legalize the non-legal arguments of call and return the
// new call with legal arguments.
return LegalizeCALL(Op, DAG);
}
// Control should come here from Legalize DAG.
// Here all the operands of CALL node should be legal.
// If this is an indirect call then to pass the arguments
// and read the return value back, we need the data address
// of the function being called.
// To get the data address two more calls need to be made.
// The flag to track if this is a direct or indirect call.
bool IsDirectCall = true;
unsigned RetVals = TheCall->getNumRetVals();
unsigned NumArgs = TheCall->getNumArgs();
SDValue DataAddr_Lo, DataAddr_Hi;
if (Callee.getOpcode() == PIC16ISD::PIC16Connect) {
IsDirectCall = false; // This is indirect call
// Read DataAddress only if we have to pass arguments or
// read return value.
if ((RetVals > 0) || (NumArgs > 0))
GetDataAddress(dl, Callee, Chain, DataAddr_Lo, DataAddr_Hi, DAG);
}
SDValue ZeroOperand = DAG.getConstant(0, MVT::i8);
// Start the call sequence.
@ -1061,45 +1229,59 @@ SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
// because there is nothing else to carry.
SDValue SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand);
Chain = getChain(SeqStart);
SDValue OperFlag = getOutFlag(SeqStart); // To manage the data dependency
std::string Name;
// For any direct call - callee will be GlobalAddressNode or
// ExternalSymbol
SDValue ArgLabel, RetLabel;
if (IsDirectCall) {
// Considering the GlobalAddressNode case here.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
GlobalValue *GV = G->getGlobal();
Callee = DAG.getTargetGlobalAddress(GV, MVT::i8);
Name = G->getGlobal()->getName();
} else {// Considering the ExternalSymbol case here
ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee);
Callee = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8);
Name = ES->getSymbol();
}
// Considering the GlobalAddressNode case here.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
GlobalValue *GV = G->getGlobal();
Callee = DAG.getTargetGlobalAddress(GV, MVT::i8);
}
// Label for argument passing
char *argFrame = new char [strlen(Name.c_str()) + 8];
sprintf(argFrame, "%s.args", Name.c_str());
ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8);
// Considering the ExternalSymbol case here
if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8);
}
// Label for reading return value
char *retName = new char [strlen(Name.c_str()) + 8];
sprintf(retName, "%s.retval", Name.c_str());
RetLabel = DAG.getTargetExternalSymbol(retName, MVT::i8);
} else {
// if indirect call
SDValue CodeAddr_Lo = Callee.getOperand(0);
SDValue CodeAddr_Hi = Callee.getOperand(1);
SDValue OperFlag = getOutFlag(Chain); // To manage the data dependency
CodeAddr_Lo = DAG.getNode(ISD::ADD, dl, MVT::i8, CodeAddr_Lo,
DAG.getConstant(2, MVT::i8));
std::string Name;
// Considering GlobalAddress here
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
Name = G->getGlobal()->getName();
// Considering ExternalSymbol here
if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee))
Name = ES->getSymbol();
char *argFrame = new char [strlen(Name.c_str()) + 8];
sprintf(argFrame, "%s.args", Name.c_str());
SDValue ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8);
char *retName = new char [strlen(Name.c_str()) + 8];
sprintf(retName, "%s.retval", Name.c_str());
SDValue RetLabel = DAG.getTargetExternalSymbol(retName, MVT::i8);
// move Hi part in PCLATH
CodeAddr_Hi = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, CodeAddr_Hi);
Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, CodeAddr_Lo,
CodeAddr_Hi);
}
// Pass the argument to function before making the call.
SDValue CallArgs = LowerCallArguments(Op, Chain, ArgLabel, OperFlag, DAG);
Chain = getChain(CallArgs);
OperFlag = getOutFlag(CallArgs);
SDValue CallArgs;
if (IsDirectCall) {
CallArgs = LowerDirectCallArguments(Op, Chain, ArgLabel, OperFlag, DAG);
Chain = getChain(CallArgs);
OperFlag = getOutFlag(CallArgs);
} else {
CallArgs = LowerIndirectCallArguments(Op, Chain, OperFlag, DataAddr_Lo,
DataAddr_Hi, DAG);
Chain = getChain(CallArgs);
OperFlag = getOutFlag(CallArgs);
}
SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag);
SDValue PICCall = DAG.getNode(PIC16ISD::CALL, dl, Tys, Chain, Callee,
@ -1116,7 +1298,11 @@ SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
OperFlag = getOutFlag(SeqEnd);
// Lower the return value reading after the call.
return LowerCallReturn(Op, Chain, RetLabel, OperFlag, DAG);
if (IsDirectCall)
return LowerDirectCallReturn(Op, Chain, RetLabel, OperFlag, DAG);
else
return LowerIndirectCallReturn(Op, Chain, OperFlag, DataAddr_Lo,
DataAddr_Hi, DAG);
}
bool PIC16TargetLowering::isDirectLoad(const SDValue Op) {

View File

@ -38,14 +38,17 @@ namespace llvm {
PIC16Store,
PIC16StWF,
Banksel,
MTLO,
MTHI,
MTLO, // Move to low part of FSR
MTHI, // Move to high part of FSR
MTPCLATH, // Move to PCLATCH
PIC16Connect, // General connector for PIC16 nodes
BCF,
LSLF, // PIC16 Logical shift left
LRLF, // PIC16 Logical shift right
RLF, // Rotate left through carry
RRF, // Rotate right through carry
CALL, // PIC16 Call instruction
CALLW, // PIC16 CALLW instruction
SUBCC, // Compare for equality or inequality.
SELECT_ICC, // Psuedo to be caught in schedular and expanded to brcond.
BRCOND, // Conditional branch.
@ -87,10 +90,25 @@ namespace llvm {
SDValue LowerBinOp(SDValue Op, SelectionDAG &DAG);
SDValue LowerCALL(SDValue Op, SelectionDAG &DAG);
SDValue LowerRET(SDValue Op, SelectionDAG &DAG);
SDValue LowerCallReturn(SDValue Op, SDValue Chain, SDValue FrameAddress,
SDValue InFlag, SelectionDAG &DAG);
SDValue LowerCallArguments(SDValue Op, SDValue Chain, SDValue FrameAddress,
SDValue InFlag, SelectionDAG &DAG);
// Call returns
SDValue
LowerDirectCallReturn(SDValue Op, SDValue Chain, SDValue FrameAddress,
SDValue InFlag, SelectionDAG &DAG);
SDValue
LowerIndirectCallReturn(SDValue Op, SDValue Chain, SDValue InFlag,
SDValue DataAddr_Lo, SDValue DataAddr_Hi,
SelectionDAG &DAG);
// Call arguments
SDValue
LowerDirectCallArguments(SDValue Op, SDValue Chain, SDValue FrameAddress,
SDValue InFlag, SelectionDAG &DAG);
SDValue
LowerIndirectCallArguments(SDValue Op, SDValue Chain, SDValue InFlag,
SDValue DataAddr_Lo, SDValue DataAddr_Hi,
SelectionDAG &DAG);
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG);
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG);
SDValue LowerStopPoint(SDValue Op, SelectionDAG &DAG);
@ -152,6 +170,18 @@ namespace llvm {
void LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG, SDValue &ES,
int &Offset);
// CALL node should have all legal operands only. Legalize all non-legal
// operands of CALL node and then return the new call will all operands
// legal.
SDValue LegalizeCALL(SDValue Op, SelectionDAG &DAG);
// For indirect calls data address of the callee frame need to be
// extracted. This function fills the arguments DataAddr_Lo and
// DataAddr_Hi with the address of the callee frame.
void GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain,
SDValue &DataAddr_Lo, SDValue &DataAddr_Hi,
SelectionDAG &DAG);
// We can not have both operands of a binary operation in W.
// This function is used to put one operand on stack and generate a load.
SDValue ConvertToMemOperand(SDValue Op, SelectionDAG &DAG, DebugLoc dl);

View File

@ -42,8 +42,12 @@ def SDT_PIC16Load : SDTypeProfile<1, 3, [SDTCisI8<0>, SDTCisI8<1>,
def SDT_PIC16Store : SDTypeProfile<0, 4, [SDTCisI8<0>, SDTCisI8<1>,
SDTCisI8<2>, SDTCisI8<3>]>;
def SDT_PIC16Connect : SDTypeProfile<1, 2, [SDTCisI8<0>, SDTCisI8<1>,
SDTCisI8<2>]>;
// PIC16ISD::CALL type prorile
def SDT_PIC16call : SDTypeProfile<0, -1, [SDTCisInt<0>]>;
def SDT_PIC16callw : SDTypeProfile<1, -1, [SDTCisInt<0>]>;
// PIC16ISD::BRCOND
def SDT_PIC16Brcond: SDTypeProfile<0, 2,
@ -79,8 +83,9 @@ def PIC16Hi : SDNode<"PIC16ISD::Hi", SDTI8UnaryOp>;
// The MTHI and MTLO nodes are used only to match them in the incoming
// DAG for replacement by corresponding set_fsrhi, set_fsrlo insntructions.
// These nodes are not used for defining any instructions.
def MTLO : SDNode<"PIC16ISD::MTLO", SDTI8UnaryOp>;
def MTHI : SDNode<"PIC16ISD::MTHI", SDTI8UnaryOp>;
def MTLO : SDNode<"PIC16ISD::MTLO", SDTI8UnaryOp>;
def MTHI : SDNode<"PIC16ISD::MTHI", SDTI8UnaryOp>;
def MTPCLATH : SDNode<"PIC16ISD::MTPCLATH", SDTI8UnaryOp>;
// Node to generate Bank Select for a GlobalAddress.
def Banksel : SDNode<"PIC16ISD::Banksel", SDTI8UnaryOp>;
@ -95,10 +100,13 @@ def PIC16Load : SDNode<"PIC16ISD::PIC16Load", SDT_PIC16Load, [SDNPHasChain]>;
def PIC16LdArg : SDNode<"PIC16ISD::PIC16LdArg", SDT_PIC16Load, [SDNPHasChain]>;
def PIC16LdWF : SDNode<"PIC16ISD::PIC16LdWF", SDT_PIC16Load,
[SDNPHasChain, SDNPInFlag, SDNPOutFlag]>;
def PIC16Connect: SDNode<"PIC16ISD::PIC16Connect", SDT_PIC16Connect, []>;
// Node to match PIC16 call
def PIC16call : SDNode<"PIC16ISD::CALL", SDT_PIC16call,
[SDNPHasChain , SDNPOptInFlag, SDNPOutFlag]>;
def PIC16callw : SDNode<"PIC16ISD::CALLW", SDT_PIC16callw,
[SDNPHasChain , SDNPOptInFlag, SDNPOutFlag]>;
// Node to match a comparison instruction.
def PIC16Subcc : SDNode<"PIC16ISD::SUBCC", SDTI8BinOp, [SDNPOutFlag]>;
@ -213,6 +221,12 @@ def set_fsrhi:
"movwf ${dst}H",
[]>;
def set_pclath:
ByteFormat<0, (outs PCLATHR:$dst),
(ins GPR:$val),
"movwf ${dst}",
[(set PCLATHR:$dst , (MTPCLATH GPR:$val))]>;
//----------------------------
// copyRegToReg
// copyRegToReg insns. These are dummy. They should always be deleted
@ -392,10 +406,23 @@ def sublw_cc : SUBLW<0, PIC16Subcc>;
// Call instruction.
let isCall = 1 in {
def CALL: LiteralFormat<0x1, (outs), (ins i8imm:$func),
"call ${func}",
"call ${func} + 2",
[(PIC16call diraddr:$func)]>;
}
let isCall = 1 in {
def CALL_1: LiteralFormat<0x1, (outs), (ins GPR:$func, PCLATHR:$pc),
"callw",
[(PIC16call (PIC16Connect GPR:$func, PCLATHR:$pc))]>;
}
let isCall = 1 in {
def CALLW: LiteralFormat<0x1, (outs GPR:$dest),
(ins GPR:$func, PCLATHR:$pc),
"callw",
[(set GPR:$dest, (PIC16callw (PIC16Connect GPR:$func, PCLATHR:$pc)))]>;
}
let Uses = [STATUS] in
def pic16brcond: ControlFormat<0x0, (outs), (ins brtarget:$dst, CCOp:$cc),
"b$cc $dst",
@ -429,7 +456,7 @@ def banksel :
// Return insn.
def Return :
ControlFormat<0, (outs), (ins), "return", [(ret)]>;
//===----------------------------------------------------------------------===//
// PIC16 Replacment Patterns.
//===----------------------------------------------------------------------===//
@ -441,9 +468,20 @@ def : Pat<(PIC16Store GPR:$val, (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr),
(set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr),
imm:$offset)>;
def : Pat<(PIC16StWF GPR:$val, (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr),
imm:$offset),
(store_indirect GPR:$val,
(set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr),
imm:$offset)>;
// Identify an indirect load and select insns for it.
def : Pat<(PIC16Load (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr),
imm:$offset),
(load_indirect (set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr),
imm:$offset)>;
def : Pat<(PIC16LdWF (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr),
imm:$offset),
(load_indirect (set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr),
imm:$offset)>;

View File

@ -20,13 +20,14 @@ def W : PIC16Reg<"W">;
def FSR0 : PIC16Reg<"FSR0">;
def FSR1 : PIC16Reg<"FSR1">;
def BS : PIC16Reg<"BS">;
def PCLATH : PIC16Reg<"PCLATH">;
def STATUS : PIC16Reg<"STATUS">;
// PIC16 Register classes.
def GPR : RegisterClass<"PIC16", [i8], 8, [W]>;
def FSR16 : RegisterClass<"PIC16", [i16], 8, [FSR0, FSR1]>;
def BSR : RegisterClass<"PIC16", [i8], 8, [BS]>;
def STATUSR: RegisterClass<"PIC16", [i8], 8, [STATUS]>;
def GPR : RegisterClass<"PIC16", [i8], 8, [W]>;
def FSR16 : RegisterClass<"PIC16", [i16], 8, [FSR0, FSR1]>;
def BSR : RegisterClass<"PIC16", [i8], 8, [BS]>;
def PCLATHR : RegisterClass<"PIC16", [i8], 8, [PCLATH]>;
def STATUSR : RegisterClass<"PIC16", [i8], 8, [STATUS]>;