mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-07 14:33:15 +00:00
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:
parent
bd6de0a2b3
commit
7836fc129a
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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)>;
|
||||
|
||||
|
@ -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]>;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user