Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4065,6 +4065,25 @@ computeKnownFPClass(V, DemandedElts, InterestedClasses, Known, Depth, Q, TLI); } +static void computeKnownFPClassForFPTrunc(const Operator *Op, + const APInt &DemandedElts, + FPClassTest InterestedClasses, + KnownFPClass &Known, unsigned Depth, + const Query &Q, + const TargetLibraryInfo *TLI) { + if ((InterestedClasses & fcNan) == fcNone) + return; + + KnownFPClass KnownSrc; + computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedClasses, + KnownSrc, Depth + 1, Q, TLI); + if (KnownSrc.isKnownNeverNaN()) + Known.knownNot(fcNan); + + // Infinity needs a range check. + // TODO: Sign bit should be preserved +} + // TODO: Merge implementation of cannotBeOrderedLessThanZero into here. void computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, KnownFPClass &Known, @@ -4348,6 +4367,11 @@ break; } + case Intrinsic::fptrunc_round: { + computeKnownFPClassForFPTrunc(Op, DemandedElts, InterestedClasses, + Known, Depth, Q, TLI); + break; + } case Intrinsic::arithmetic_fence: { computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses, Known, Depth + 1, Q, TLI); @@ -4480,16 +4504,8 @@ break; } case Instruction::FPTrunc: { - if ((InterestedClasses & fcNan) == fcNone) - break; - - KnownFPClass KnownSrc; - computeKnownFPClass(Op->getOperand(0), DemandedElts, - InterestedClasses, KnownSrc, Depth + 1, Q, TLI); - if (KnownSrc.isKnownNeverNaN()) - Known.knownNot(fcNan); - - // Infinity needs a range check. + computeKnownFPClassForFPTrunc(Op, DemandedElts, InterestedClasses, Known, + Depth, Q, TLI); break; } case Instruction::SIToFP: Index: llvm/test/Transforms/Attributor/nofpclass-fptrunc.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-fptrunc.ll +++ llvm/test/Transforms/Attributor/nofpclass-fptrunc.ll @@ -1,9 +1,11 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +declare float @llvm.fptrunc.round.f32.f64(double, metadata) + define float @ret_fptrunc(double %arg0) { ; CHECK-LABEL: define float @ret_fptrunc -; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -13,7 +15,7 @@ define float @ret_fptrunc_nonan(double nofpclass(nan) %arg0) { ; CHECK-LABEL: define nofpclass(nan) float @ret_fptrunc_nonan -; CHECK-SAME: (double nofpclass(nan) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(nan) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -23,7 +25,7 @@ define float @ret_fptrunc_noqnan(double nofpclass(qnan) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_noqnan -; CHECK-SAME: (double nofpclass(qnan) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(qnan) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -33,7 +35,7 @@ define float @ret_fptrunc_nosnan(double nofpclass(snan) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nosnan -; CHECK-SAME: (double nofpclass(snan) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(snan) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -43,7 +45,7 @@ define float @ret_fptrunc_noinf(double nofpclass(inf) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_noinf -; CHECK-SAME: (double nofpclass(inf) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(inf) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -53,7 +55,7 @@ define float @ret_fptrunc_nopinf(double nofpclass(pinf) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nopinf -; CHECK-SAME: (double nofpclass(pinf) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(pinf) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -63,7 +65,7 @@ define float @ret_fptrunc_noninf(double nofpclass(ninf) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_noninf -; CHECK-SAME: (double nofpclass(ninf) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(ninf) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -73,7 +75,7 @@ define float @ret_fptrunc_nozero(double nofpclass(zero) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nozero -; CHECK-SAME: (double nofpclass(zero) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(zero) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -83,7 +85,7 @@ define float @ret_fptrunc_nopzero(double nofpclass(pzero) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nopzero -; CHECK-SAME: (double nofpclass(pzero) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(pzero) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -93,7 +95,7 @@ define float @ret_fptrunc_nonzero(double nofpclass(nzero) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nonzero -; CHECK-SAME: (double nofpclass(nzero) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(nzero) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -103,7 +105,7 @@ define float @ret_fptrunc_nonan_noinf(double nofpclass(nan inf) %arg0) { ; CHECK-LABEL: define nofpclass(nan) float @ret_fptrunc_nonan_noinf -; CHECK-SAME: (double nofpclass(nan inf) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(nan inf) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -113,7 +115,7 @@ define float @ret_fptrunc_nosub(double nofpclass(sub) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nosub -; CHECK-SAME: (double nofpclass(sub) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(sub) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; @@ -123,12 +125,142 @@ define float @ret_fptrunc_nonorm(double nofpclass(norm) %arg0) { ; CHECK-LABEL: define float @ret_fptrunc_nonorm -; CHECK-SAME: (double nofpclass(norm) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-SAME: (double nofpclass(norm) [[ARG0:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[EXT:%.*]] = fptrunc double [[ARG0]] to float ; CHECK-NEXT: ret float [[EXT]] ; %ext = fptrunc double %arg0 to float ret float %ext } + +define float @ret_fptrunc_round(double %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round +; CHECK-SAME: (double [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2:[0-9]+]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nonan(double nofpclass(nan) %arg0) { +; CHECK-LABEL: define nofpclass(nan) float @ret_fptrunc_round_nonan +; CHECK-SAME: (double nofpclass(nan) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call nofpclass(nan) float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_noqnan(double nofpclass(qnan) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_noqnan +; CHECK-SAME: (double nofpclass(qnan) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nosnan(double nofpclass(snan) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nosnan +; CHECK-SAME: (double nofpclass(snan) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_noinf(double nofpclass(inf) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_noinf +; CHECK-SAME: (double nofpclass(inf) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nopinf(double nofpclass(pinf) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nopinf +; CHECK-SAME: (double nofpclass(pinf) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_noninf(double nofpclass(ninf) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_noninf +; CHECK-SAME: (double nofpclass(ninf) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nozero(double nofpclass(zero) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nozero +; CHECK-SAME: (double nofpclass(zero) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nopzero(double nofpclass(pzero) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nopzero +; CHECK-SAME: (double nofpclass(pzero) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nonzero(double nofpclass(nzero) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nonzero +; CHECK-SAME: (double nofpclass(nzero) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nonan_noinf(double nofpclass(nan inf) %arg0) { +; CHECK-LABEL: define nofpclass(nan) float @ret_fptrunc_round_nonan_noinf +; CHECK-SAME: (double nofpclass(nan inf) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call nofpclass(nan) float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nosub(double nofpclass(sub) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nosub +; CHECK-SAME: (double nofpclass(sub) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} + +define float @ret_fptrunc_round_nonorm(double nofpclass(norm) %arg0) { +; CHECK-LABEL: define float @ret_fptrunc_round_nonorm +; CHECK-SAME: (double nofpclass(norm) [[ARG0:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: [[EXT:%.*]] = call float @llvm.fptrunc.round.f32.f64(double [[ARG0]], metadata !"round.downward") #[[ATTR2]] +; CHECK-NEXT: ret float [[EXT]] +; + %ext = call float @llvm.fptrunc.round.f32.f64(double %arg0, metadata !"round.downward") + ret float %ext +} ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: ; TUNIT: {{.*}}