+ SDValue TmpE2, TmpY3, TmpQ0, TmpR0;
+
+ SDValue OpsE2[] = { TmpE1, TmpE1, F0, TmpPR };
+ TmpE2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, MVT::f64,
+ OpsE2, 4), 0);
+ Chain = TmpE2.getValue(1);
+ SDValue OpsY3[] = { TmpY2, TmpE2, TmpY2, TmpPR };
+ TmpY3 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, MVT::f64,
+ OpsY3, 4), 0);
+ Chain = TmpY3.getValue(1);
+ SDValue OpsQ0[] = { Tmp1, TmpY3, F0, TmpPR };
+ TmpQ0 =
+ SDValue(CurDAG->getTargetNode(IA64::CFMADS1, MVT::f64, // double prec!
+ OpsQ0, 4), 0);
+ Chain = TmpQ0.getValue(1);
+ SDValue OpsR0[] = { Tmp2, TmpQ0, Tmp1, TmpPR };
+ TmpR0 =
+ SDValue(CurDAG->getTargetNode(IA64::CFNMADS1, MVT::f64, // double prec!
+ OpsR0, 4), 0);
+ Chain = TmpR0.getValue(1);
+
+// we want Result to have the same target register as the frcpa, so
+// we two-address hack it. See the comment "for this to work..." on
+// page 48 of Intel application note #245415
+ SDValue Ops[] = { TmpF5, TmpY3, TmpR0, TmpQ0, TmpPR };
+ Result = CurDAG->getTargetNode(IA64::TCFMADS0, MVT::f64, // d.p. s0 rndg!
+ Ops, 5);
+ Chain = SDValue(Result, 1);
+ return Result; // XXX: early exit!
+ } else { // this is *not* an FP divide, so there's a bit left to do:
+
+ SDValue TmpQ2, TmpR2, TmpQ3, TmpQ;
+
+ SDValue OpsQ2[] = { TmpF3, TmpY2, F0, TmpPR };
+ TmpQ2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, MVT::f64,
+ OpsQ2, 4), 0);
+ Chain = TmpQ2.getValue(1);
+ SDValue OpsR2[] = { TmpF4, TmpQ2, TmpF3, TmpPR };
+ TmpR2 = SDValue(CurDAG->getTargetNode(IA64::CFNMAS1, MVT::f64,
+ OpsR2, 4), 0);
+ Chain = TmpR2.getValue(1);
+
+// we want TmpQ3 to have the same target register as the frcpa? maybe we
+// should two-address hack it. See the comment "for this to work..." on page
+// 48 of Intel application note #245415
+ SDValue OpsQ3[] = { TmpF5, TmpR2, TmpY2, TmpQ2, TmpPR };
+ TmpQ3 = SDValue(CurDAG->getTargetNode(IA64::TCFMAS1, MVT::f64,
+ OpsQ3, 5), 0);
+ Chain = TmpQ3.getValue(1);
+
+ // STORY: without these two-address instructions (TCFMAS1 and TCFMADS0)
+ // the FPSWA won't be able to help out in the case of large/tiny
+ // arguments. Other fun bugs may also appear, e.g. 0/x = x, not 0.
+
+ if(isSigned)
+ TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXTRUNCS1,
+ MVT::f64, TmpQ3), 0);
+ else
+ TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXUTRUNCS1,
+ MVT::f64, TmpQ3), 0);
+
+ Chain = TmpQ.getValue(1);
+
+ if(isModulus) {
+ SDValue FPminusB =
+ SDValue(CurDAG->getTargetNode(IA64::SETFSIG, MVT::f64, minusB), 0);
+ Chain = FPminusB.getValue(1);
+ SDValue Remainder =
+ SDValue(CurDAG->getTargetNode(IA64::XMAL, MVT::f64,
+ TmpQ, FPminusB, TmpF1), 0);
+ Chain = Remainder.getValue(1);
+ Result = CurDAG->getTargetNode(IA64::GETFSIG, MVT::i64, Remainder);
+ Chain = SDValue(Result, 1);
+ } else { // just an integer divide
+ Result = CurDAG->getTargetNode(IA64::GETFSIG, MVT::i64, TmpQ);
+ Chain = SDValue(Result, 1);
+ }