From 5cdf75084a6606b12ea08e0a1eb8e68714b4b75f Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Thu, 17 Mar 2016 22:27:58 +0000 Subject: [PATCH] [PPC, FastISel] Fix ordered/unordered fcmp For fcmp, major concern about the following 6 cases is NaN result. The comparison result consists of 4 bits, indicating lt, eq, gt and un (unordered), only one of which will be set. The result is generated by fcmpu instruction. However, bc instruction only inspects one of the first 3 bits, so when un is set, bc instruction may jump to to an undesired place. More specifically, if we expect an unordered comparison and un is set, we expect to always go to true branch; in such case UEQ, UGT and ULT still give false, which are undesired; but UNE, UGE, ULE happen to give true, since they are tested by inspecting !eq, !lt, !gt, respectively. Similarly, for ordered comparison, when un is set, we always expect the result to be false. In such case OGT, OLT and OEQ is good, since they are actually testing GT, LT, and EQ respectively, which are false. OGE, OLE and ONE are tested through !lt, !gt and !eq, and these are true. llvm-svn: 263753 --- llvm/lib/Target/PowerPC/PPCFastISel.cpp | 30 +++- llvm/test/CodeGen/PowerPC/fast-isel-fcmp-nan.ll | 187 ++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 llvm/test/CodeGen/PowerPC/fast-isel-fcmp-nan.ll diff --git a/llvm/lib/Target/PowerPC/PPCFastISel.cpp b/llvm/lib/Target/PowerPC/PPCFastISel.cpp index 1de2679..360fbb6 100644 --- a/llvm/lib/Target/PowerPC/PPCFastISel.cpp +++ b/llvm/lib/Target/PowerPC/PPCFastISel.cpp @@ -213,13 +213,29 @@ static Optional getComparePred(CmpInst::Predicate Pred) { switch (Pred) { // These are not representable with any single compare. case CmpInst::FCMP_FALSE: + case CmpInst::FCMP_TRUE: + // Major concern about the following 6 cases is NaN result. The comparison + // result consists of 4 bits, indicating lt, eq, gt and un (unordered), + // only one of which will be set. The result is generated by fcmpu + // instruction. However, bc instruction only inspects one of the first 3 + // bits, so when un is set, bc instruction may jump to to an undesired + // place. + // + // More specifically, if we expect an unordered comparison and un is set, we + // expect to always go to true branch; in such case UEQ, UGT and ULT still + // give false, which are undesired; but UNE, UGE, ULE happen to give true, + // since they are tested by inspecting !eq, !lt, !gt, respectively. + // + // Similarly, for ordered comparison, when un is set, we always expect the + // result to be false. In such case OGT, OLT and OEQ is good, since they are + // actually testing GT, LT, and EQ respectively, which are false. OGE, OLE + // and ONE are tested through !lt, !gt and !eq, and these are true. case CmpInst::FCMP_UEQ: case CmpInst::FCMP_UGT: - case CmpInst::FCMP_UGE: case CmpInst::FCMP_ULT: - case CmpInst::FCMP_ULE: - case CmpInst::FCMP_UNE: - case CmpInst::FCMP_TRUE: + case CmpInst::FCMP_OGE: + case CmpInst::FCMP_OLE: + case CmpInst::FCMP_ONE: default: return Optional(); @@ -232,7 +248,7 @@ static Optional getComparePred(CmpInst::Predicate Pred) { case CmpInst::ICMP_SGT: return PPC::PRED_GT; - case CmpInst::FCMP_OGE: + case CmpInst::FCMP_UGE: case CmpInst::ICMP_UGE: case CmpInst::ICMP_SGE: return PPC::PRED_GE; @@ -242,12 +258,12 @@ static Optional getComparePred(CmpInst::Predicate Pred) { case CmpInst::ICMP_SLT: return PPC::PRED_LT; - case CmpInst::FCMP_OLE: + case CmpInst::FCMP_ULE: case CmpInst::ICMP_ULE: case CmpInst::ICMP_SLE: return PPC::PRED_LE; - case CmpInst::FCMP_ONE: + case CmpInst::FCMP_UNE: case CmpInst::ICMP_NE: return PPC::PRED_NE; diff --git a/llvm/test/CodeGen/PowerPC/fast-isel-fcmp-nan.ll b/llvm/test/CodeGen/PowerPC/fast-isel-fcmp-nan.ll new file mode 100644 index 0000000..4390b93 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/fast-isel-fcmp-nan.ll @@ -0,0 +1,187 @@ +; RUN: llc -mtriple powerpc64le-unknown-linux-gnu -fast-isel -O0 < %s | FileCheck %s + +define i1 @TestULT(double %t0) { +; CHECK-LABEL: TestULT: +; CHECK: mcrf +; CHECK: blr +entry: + %t1 = fcmp ult double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestULE(double %t0) { +; CHECK-LABEL: TestULE: +; CHECK: fcmpu +; CHECK-NEXT: ble +; CHECK: blr +entry: + %t1 = fcmp ule double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestUNE(double %t0) { +; CHECK-LABEL: TestUNE: +; CHECK: fcmpu +; CHECK-NEXT: bne +; CHECK: blr +entry: + %t1 = fcmp une double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestUEQ(double %t0) { +; CHECK-LABEL: TestUEQ: +; CHECK: mcrf +; CHECK: blr +entry: + %t1 = fcmp ueq double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestUGT(double %t0) { +; CHECK-LABEL: TestUGT: +; CHECK: mcrf +; CHECK: blr +entry: + %t1 = fcmp ugt double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestUGE(double %t0) { +; CHECK-LABEL: TestUGE: +; CHECK: fcmpu +; CHECK-NEXT: bge +; CHECK: blr +entry: + %t1 = fcmp uge double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestOLT(double %t0) { +; CHECK-LABEL: TestOLT: +; CHECK: fcmpu +; CHECK-NEXT: blt +; CHECK: blr +entry: + %t1 = fcmp olt double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestOLE(double %t0) { +; CHECK-LABEL: TestOLE: +; CHECK: mcrf +; CHECK: blr +entry: + %t1 = fcmp ole double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestONE(double %t0) { +; CHECK-LABEL: TestONE: +; CHECK: mcrf +; CHECK: blr +entry: + %t1 = fcmp one double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestOEQ(double %t0) { +; CHECK-LABEL: TestOEQ: +; CHECK: fcmpu +; CHECK-NEXT: beq +; CHECK: blr +entry: + %t1 = fcmp oeq double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestOGT(double %t0) { +; CHECK-LABEL: TestOGT: +; CHECK: fcmpu +; CHECK-NEXT: bgt +; CHECK: blr +entry: + %t1 = fcmp ogt double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} + +define i1 @TestOGE(double %t0) { +; CHECK-LABEL: TestOGE: +; CHECK: mcrf +; CHECK: blr +entry: + %t1 = fcmp oge double %t0, 0.000000e+00 + br i1 %t1, label %good, label %bad + +bad: + ret i1 false + +good: + ret i1 true +} -- 2.7.4