getI64Imm(Amt), Select(N->getOperand(0)));
}
- case ISD::RET: {
- SDOperand Chain = Select(N->getOperand(0)); // Token chain.
- SDOperand InFlag;
-
- switch (N->getNumOperands()) {
- default:
- assert(0 && "Unknown return instruction!");
- case 2: {
- SDOperand RetVal = Select(N->getOperand(1));
- switch (RetVal.getValueType()) {
- default: assert(0 && "I don't know how to return this type! (promote?)");
- // FIXME: do I need to add support for bools here?
- // (return '0' or '1' in r8, basically...)
- //
- // FIXME: need to round floats - 80 bits is bad, the tester
- // told me so
- case MVT::i64:
- // we mark r8 as live on exit up above in LowerArguments()
- // BuildMI(BB, IA64::MOV, 1, IA64::r8).addReg(Tmp1);
- Chain = CurDAG->getCopyToReg(Chain, IA64::r8, RetVal);
- InFlag = Chain.getValue(1);
- break;
- case MVT::f64:
- // we mark F8 as live on exit up above in LowerArguments()
- // BuildMI(BB, IA64::FMOV, 1, IA64::F8).addReg(Tmp1);
- Chain = CurDAG->getCopyToReg(Chain, IA64::F8, RetVal);
- InFlag = Chain.getValue(1);
- break;
- }
- break;
- }
- case 1:
- break;
- }
-
- // we need to copy VirtGPR (the vreg (to become a real reg)) that holds
- // the output of this function's alloc instruction back into ar.pfs
- // before we return. this copy must not float up above the last
- // outgoing call in this function!!!
- SDOperand AR_PFSVal = CurDAG->getCopyFromReg(Chain, IA64Lowering.VirtGPR,
- MVT::i64);
- Chain = AR_PFSVal.getValue(1);
- Chain = CurDAG->getCopyToReg(Chain, IA64::AR_PFS, AR_PFSVal);
-
- // and then just emit a 'ret' instruction
- // before returning, restore the ar.pfs register (set by the 'alloc' up top)
- // BuildMI(BB, IA64::MOV, 1).addReg(IA64::AR_PFS).addReg(IA64Lowering.VirtGPR);
- //
- return CurDAG->SelectNodeTo(N, IA64::RET, MVT::Other, Chain);
- }
-
case ISD::BR:
// FIXME: we don't need long branches all the time!
return CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other,
setOperationAction(ISD::BRTWOWAY_CC , MVT::Other, Expand);
setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand);
+ // We need to handle ISD::RET for void functions ourselves,
+ // so we get a chance to restore ar.pfs before adding a
+ // br.ret insn
+ setOperationAction(ISD::RET, MVT::Other, Custom);
+
setSetCCResultType(MVT::i1);
setShiftAmountType(MVT::i64);
default: return 0;
case IA64ISD::GETFD: return "IA64ISD::GETFD";
case IA64ISD::BRCALL: return "IA64ISD::BRCALL";
+ case IA64ISD::RET_FLAG: return "IA64ISD::RET_FLAG";
}
}
return std::make_pair(RetVal, Chain);
}
+SDOperand IA64TargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op,
+ SelectionDAG &DAG) {
+ SDOperand Copy, InFlag;
+ SDOperand AR_PFSVal = DAG.getCopyFromReg(Chain, this->VirtGPR,
+ MVT::i64);
+ Chain = AR_PFSVal.getValue(1);
+
+ switch (Op.getValueType()) {
+ default: assert(0 && "Unknown type to return! (promote?)");
+ case MVT::i64:
+ Copy = DAG.getCopyToReg(Chain, IA64::r8, Op, InFlag);
+ break;
+ case MVT::f64:
+ Copy = DAG.getCopyToReg(Chain, IA64::F8, Op, InFlag);
+ break;
+ }
+
+ Chain = Copy.getValue(0);
+ InFlag = Copy.getValue(1);
+ // we need to copy VirtGPR (the vreg (to become a real reg)) that holds
+ // the output of this function's alloc instruction back into ar.pfs
+ // before we return. this copy must not float up above the last
+ // outgoing call in this function - we flag this to the ret instruction
+ Chain = DAG.getCopyToReg(Chain, IA64::AR_PFS, AR_PFSVal, InFlag);
+ InFlag = Chain.getValue(1);
+
+ // and then just emit a 'ret' instruction
+ std::vector<MVT::ValueType> NodeTys;
+ std::vector<SDOperand> RetOperands;
+ NodeTys.push_back(MVT::Other);
+ NodeTys.push_back(MVT::Flag);
+ RetOperands.push_back(Chain);
+ RetOperands.push_back(InFlag);
+
+ return DAG.getNode(IA64ISD::RET_FLAG, NodeTys, RetOperands);
+// return DAG.getNode(IA64ISD::RET_FLAG, MVT::Other, MVT::Other, Copy, Chain, InFlag);
+}
+
SDOperand
IA64TargetLowering::LowerVAStart(SDOperand Chain, SDOperand VAListP,
Value *VAListV, SelectionDAG &DAG) {
abort();
}
+SDOperand IA64TargetLowering::
+LowerOperation(SDOperand Op, SelectionDAG &DAG) {
+ switch (Op.getOpcode()) {
+ default: assert(0 && "Should not custom lower this!");
+ case ISD::RET: { // the DAGgy stuff takes care of
+ // restoring ar.pfs before adding a br.ret for functions
+ // that return something, but we need to take care of stuff
+ // that returns void manually, so here it is:
+ assert(Op.getNumOperands()==1 &&
+ "trying to custom lower a return other than void! (numops!=1)");
+
+ SDOperand Chain = Op.getOperand(0);
+ SDOperand AR_PFSVal = DAG.getCopyFromReg(Chain, this->VirtGPR,
+ MVT::i64);
+ Chain = AR_PFSVal.getValue(1);
+ Chain = DAG.getCopyToReg(Chain, IA64::AR_PFS, AR_PFSVal);
+
+ // and then just emit a 'ret' instruction
+ return DAG.getNode(IA64ISD::RET_FLAG, MVT::Other, Chain);
+ }
+ }
+}
GETFD,
// TODO: explain this hack
- BRCALL
+ BRCALL,
+
+ // RET_FLAG - Return with a flag operand
+ RET_FLAG
};
}
bool isTailCall, SDOperand Callee, ArgListTy &Args,
SelectionDAG &DAG);
+ /// LowerReturnTo - This spits out restore-previous-frame-state+br.ret
+ /// instructions
+ virtual SDOperand LowerReturnTo(SDOperand Chain, SDOperand Op,
+ SelectionDAG &DAG);
+
+ /// LowerOperation - for custom lowering specific ops
+ /// (currently, only "ret void")
+ virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
+
virtual SDOperand LowerVAStart(SDOperand Chain, SDOperand VAListP,
Value *VAListV, SelectionDAG &DAG);
-
+
virtual std::pair<SDOperand,SDOperand>
LowerVAArg(SDOperand Chain, SDOperand VAListP, Value *VAListV,
const Type *ArgTy, SelectionDAG &DAG);
def IA64getfd : SDNode<"IA64ISD::GETFD", SDTFPToIntOp, []>;
+def SDT_IA64RetFlag : SDTypeProfile<0, 0, []>;
+def retflag : SDNode<"IA64ISD::RET_FLAG", SDT_IA64RetFlag,
+ [SDNPHasChain, SDNPOptInFlag]>;
+
//===---------
def u2imm : Operand<i8>;
"($qp) br.cond.call.sptk $dst;;">;
}
+// Return branch:
let isTerminator = 1, isReturn = 1, noResults = 1 in
- def RET : RawForm<0x03, 0xb0, (ops), "br.ret.sptk.many rp;;">; // return
-
-
+ def RET : AForm_DAG<0x03, 0x0b, (ops),
+ "br.ret.sptk.many rp;;",
+ [(retflag)]>; // return
+def : Pat<(ret), (RET)>;