- if(isModulus) { // XXX: fragile! fixes _only_ mod, *breaks* div! !
- SDOperand bogus = CurDAG->getTargetNode(IA64::IUSE, MVT::Other, TmpF13); // hack :(
- Chain = bogus.getValue(0); // hmmm
- }
-
- if(!isFP) {
- // round to an integer
- if(isSigned) {
- TmpF15 = CurDAG->getTargetNode(IA64::FCVTFXTRUNCS1, MVT::i64, TmpF14);
- Chain = TmpF15.getValue(1);
- }
- else {
- TmpF15 = CurDAG->getTargetNode(IA64::FCVTFXUTRUNCS1, MVT::i64, TmpF14);
- Chain = TmpF15.getValue(1);
- }
- } else {
- TmpF15 = TmpF14;
- // EXERCISE: can you see why TmpF15=TmpF14 does not work here, and
- // we really do need the above FMOV? ;)
- }
-
- if(!isModulus) {
- if(isFP) { // extra worrying about div-by-zero
- // we do a 'conditional fmov' (of the correct result, depending
- // on how the frcpa predicate turned out)
- SDOperand bogoResult = CurDAG->getTargetNode(IA64::PFMOV, MVT::f64,
- TmpF12, TmpPR2);
- Chain = bogoResult.getValue(1);
- Result = CurDAG->getTargetNode(IA64::CFMOV, MVT::f64, bogoResult,
- TmpF15, TmpPR);
- Chain = Result.getValue(1);
- }
- else {
- Result = CurDAG->getTargetNode(IA64::GETFSIG, MVT::i64, TmpF15);
- Chain = Result.getValue(1);
- }
- } else { // this is a modulus
- if(!isFP) {
- // answer = q * (-b) + a
- SDOperand TmpI = CurDAG->getTargetNode(IA64::SUB, MVT::i64,
- CurDAG->getRegister(IA64::r0, MVT::i64), Tmp2);
- Chain = TmpI.getValue(1);
- SDOperand TmpF = CurDAG->getTargetNode(IA64::SETFSIG, MVT::f64, TmpI);
- Chain = TmpF.getValue(1);
- SDOperand ModulusResult = CurDAG->getTargetNode(IA64::XMAL, MVT::f64,
- TmpF15, TmpF, TmpF1);
- Chain = ModulusResult.getValue(1);
- Result = CurDAG->getTargetNode(IA64::GETFSIG, MVT::i64, ModulusResult);
- Chain = Result.getValue(1);
- } else { // FP modulus! The horror... the horror....
- assert(0 && "sorry, no FP modulus just yet!\n!\n");
+ if(isFP) { // if this is an FP divide, we finish up here and exit early
+ if(isModulus)
+ assert(0 && "Sorry, try another FORTRAN compiler.");
+
+ SDValue TmpE2, TmpY3, TmpQ0, TmpR0;
+
+ SDValue OpsE2[] = { TmpE1, TmpE1, F0, TmpPR };
+ TmpE2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
+ OpsE2, 4), 0);
+ Chain = TmpE2.getValue(1);
+ SDValue OpsY3[] = { TmpY2, TmpE2, TmpY2, TmpPR };
+ TmpY3 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64,
+ OpsY3, 4), 0);
+ Chain = TmpY3.getValue(1);
+ SDValue OpsQ0[] = { Tmp1, TmpY3, F0, TmpPR };
+ TmpQ0 =
+ SDValue(CurDAG->getTargetNode(IA64::CFMADS1, dl, // double prec!
+ MVT::f64, OpsQ0, 4), 0);
+ Chain = TmpQ0.getValue(1);
+ SDValue OpsR0[] = { Tmp2, TmpQ0, Tmp1, TmpPR };
+ TmpR0 =
+ SDValue(CurDAG->getTargetNode(IA64::CFNMADS1, dl, // double prec!
+ MVT::f64, 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, dl, // d.p. s0 rndg!
+ MVT::f64, 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, dl, MVT::f64,
+ OpsQ2, 4), 0);
+ Chain = TmpQ2.getValue(1);
+ SDValue OpsR2[] = { TmpF4, TmpQ2, TmpF3, TmpPR };
+ TmpR2 = SDValue(CurDAG->getTargetNode(IA64::CFNMAS1, dl, 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, dl, 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, dl,
+ MVT::f64, TmpQ3), 0);
+ else
+ TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXUTRUNCS1, dl,
+ MVT::f64, TmpQ3), 0);
+
+ Chain = TmpQ.getValue(1);
+
+ if(isModulus) {
+ SDValue FPminusB =
+ SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, minusB),
+ 0);
+ Chain = FPminusB.getValue(1);
+ SDValue Remainder =
+ SDValue(CurDAG->getTargetNode(IA64::XMAL, dl, MVT::f64,
+ TmpQ, FPminusB, TmpF1), 0);
+ Chain = Remainder.getValue(1);
+ Result = CurDAG->getTargetNode(IA64::GETFSIG, dl, MVT::i64, Remainder);
+ Chain = SDValue(Result, 1);
+ } else { // just an integer divide
+ Result = CurDAG->getTargetNode(IA64::GETFSIG, dl, MVT::i64, TmpQ);
+ Chain = SDValue(Result, 1);