From ed6af24e146a5d358115123f0d2be694c1fa3a84 Mon Sep 17 00:00:00 2001 From: Dale Johannesen Date: Wed, 21 Jan 2009 00:35:19 +0000 Subject: [PATCH] Make special cases (0 inf nan) work for frem. Besides APFloat, this involved removing code from two places that thought they knew the result of frem(0., x) but were wrong. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62645 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/APFloat.h | 1 + lib/Support/APFloat.cpp | 86 +++-- .../Scalar/InstructionCombining.cpp | 10 +- lib/VMCore/ConstantFold.cpp | 10 - ...2009-01-19-fmod-constant-float-specials.ll | 315 ++++++++++++++++++ 5 files changed, 384 insertions(+), 38 deletions(-) create mode 100644 test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 5b09d48b0f0..29a89dd06c2 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -293,6 +293,7 @@ namespace llvm { opStatus addOrSubtractSpecials(const APFloat &, bool subtract); opStatus divideSpecials(const APFloat &); opStatus multiplySpecials(const APFloat &); + opStatus modSpecials(const APFloat &); /* Miscellany. */ void makeNaN(void); diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 151f9d5b392..c296770385f 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -1405,6 +1405,42 @@ APFloat::divideSpecials(const APFloat &rhs) } } +APFloat::opStatus +APFloat::modSpecials(const APFloat &rhs) +{ + switch(convolve(category, rhs.category)) { + default: + assert(0); + + case convolve(fcNaN, fcZero): + case convolve(fcNaN, fcNormal): + case convolve(fcNaN, fcInfinity): + case convolve(fcNaN, fcNaN): + case convolve(fcZero, fcInfinity): + case convolve(fcZero, fcNormal): + case convolve(fcNormal, fcInfinity): + return opOK; + + case convolve(fcZero, fcNaN): + case convolve(fcNormal, fcNaN): + case convolve(fcInfinity, fcNaN): + category = fcNaN; + copySignificand(rhs); + return opOK; + + case convolve(fcNormal, fcZero): + case convolve(fcInfinity, fcZero): + case convolve(fcInfinity, fcNormal): + case convolve(fcInfinity, fcInfinity): + case convolve(fcZero, fcZero): + makeNaN(); + return opInvalidOp; + + case convolve(fcNormal, fcNormal): + return opOK; + } +} + /* Change sign. */ void APFloat::changeSign() @@ -1557,35 +1593,39 @@ APFloat::opStatus APFloat::mod(const APFloat &rhs, roundingMode rounding_mode) { opStatus fs; - APFloat V = *this; - unsigned int origSign = sign; - assertArithmeticOK(*semantics); - fs = V.divide(rhs, rmNearestTiesToEven); - if (fs == opDivByZero) - return fs; + fs = modSpecials(rhs); - int parts = partCount(); - integerPart *x = new integerPart[parts]; - bool ignored; - fs = V.convertToInteger(x, parts * integerPartWidth, true, - rmTowardZero, &ignored); - if (fs==opInvalidOp) - return fs; + if (category == fcNormal && rhs.category == fcNormal) { + APFloat V = *this; + unsigned int origSign = sign; - fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true, - rmNearestTiesToEven); - assert(fs==opOK); // should always work + fs = V.divide(rhs, rmNearestTiesToEven); + if (fs == opDivByZero) + return fs; - fs = V.multiply(rhs, rounding_mode); - assert(fs==opOK || fs==opInexact); // should not overflow or underflow + int parts = partCount(); + integerPart *x = new integerPart[parts]; + bool ignored; + fs = V.convertToInteger(x, parts * integerPartWidth, true, + rmTowardZero, &ignored); + if (fs==opInvalidOp) + return fs; - fs = subtract(V, rounding_mode); - assert(fs==opOK || fs==opInexact); // likewise + fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true, + rmNearestTiesToEven); + assert(fs==opOK); // should always work - if (isZero()) - sign = origSign; // IEEE754 requires this - delete[] x; + fs = V.multiply(rhs, rounding_mode); + assert(fs==opOK || fs==opInexact); // should not overflow or underflow + + fs = subtract(V, rounding_mode); + assert(fs==opOK || fs==opInexact); // likewise + + if (isZero()) + sign = origSign; // IEEE754 requires this + delete[] x; + } return fs; } diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index c02fabd9c0c..f038cd02a93 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -2954,11 +2954,6 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { Instruction *InstCombiner::commonRemTransforms(BinaryOperator &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); - // 0 % X == 0 for integer, we don't need to preserve faults! - if (Constant *LHS = dyn_cast(Op0)) - if (LHS->isNullValue()) - return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); - if (isa(Op0)) { // undef % X -> 0 if (I.getType()->isFPOrFPVector()) return ReplaceInstUsesWith(I, Op0); // X % undef -> undef (could be SNaN) @@ -2984,6 +2979,11 @@ Instruction *InstCombiner::commonIRemTransforms(BinaryOperator &I) { if (Instruction *common = commonRemTransforms(I)) return common; + // 0 % X == 0 for integer, we don't need to preserve faults! + if (Constant *LHS = dyn_cast(Op0)) + if (LHS->isNullValue()) + return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); + if (ConstantInt *RHS = dyn_cast(Op1)) { // X % 0 == undef, we don't need to preserve faults! if (RHS->equalsInt(0)) diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index 0c5297fccb3..5c1578f74b0 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -802,16 +802,6 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, (void)C3V.divide(C2V, APFloat::rmNearestTiesToEven); return ConstantFP::get(C3V); case Instruction::FRem: - if (C2V.isZero()) { - // IEEE 754, Section 7.1, #5 - if (CFP1->getType() == Type::DoubleTy) - return ConstantFP::get(APFloat(std::numeric_limits:: - quiet_NaN())); - if (CFP1->getType() == Type::FloatTy) - return ConstantFP::get(APFloat(std::numeric_limits:: - quiet_NaN())); - break; - } (void)C3V.mod(C2V, APFloat::rmNearestTiesToEven); return ConstantFP::get(C3V); } diff --git a/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll b/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll new file mode 100644 index 00000000000..fdcafca66c6 --- /dev/null +++ b/test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll @@ -0,0 +1,315 @@ +; RUN: llvm-as < %s | opt -simplifycfg -instcombine | llvm-dis | grep 0x7FF8000000000000 | count 7 +; RUN: llvm-as < %s | opt -simplifycfg -instcombine | llvm-dis | grep 0x7FF80000FFFFFFFF | count 5 +; RUN: llvm-as < %s | opt -simplifycfg -instcombine | llvm-dis | grep {0\\.0} | count 3 +; RUN: llvm-as < %s | opt -simplifycfg -instcombine | llvm-dis | grep {3\\.5} | count 1 + +; ModuleID = 'apf.c' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin9.6" +@"\01LC" = internal constant [4 x i8] c"%f\0A\00" ; <[4 x i8]*> [#uses=1] + +define void @foo1() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF0000000000000, float* %x, align 4 + store float 0x7FF8000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +declare i32 @printf(i8*, ...) nounwind + +define void @foo2() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF0000000000000, float* %x, align 4 + store float 0.000000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo3() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF0000000000000, float* %x, align 4 + store float 3.500000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo4() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF0000000000000, float* %x, align 4 + store float 0x7FF0000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo5() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF8000000000000, float* %x, align 4 + store float 0x7FF0000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo6() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF8000000000000, float* %x, align 4 + store float 0.000000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo7() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF8000000000000, float* %x, align 4 + store float 3.500000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo8() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0x7FF8000000000000, float* %x, align 4 + store float 0x7FF8000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo9() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0.000000e+00, float* %x, align 4 + store float 0x7FF8000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo10() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0.000000e+00, float* %x, align 4 + store float 0x7FF0000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo11() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0.000000e+00, float* %x, align 4 + store float 0.000000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo12() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 0.000000e+00, float* %x, align 4 + store float 3.500000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo13() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 3.500000e+00, float* %x, align 4 + store float 0x7FF8000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo14() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 3.500000e+00, float* %x, align 4 + store float 0x7FF0000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo15() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 3.500000e+00, float* %x, align 4 + store float 0.000000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo16() nounwind { +entry: + %y = alloca float ; [#uses=2] + %x = alloca float ; [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store float 3.500000e+00, float* %x, align 4 + store float 3.500000e+00, float* %y, align 4 + %0 = load float* %y, align 4 ; [#uses=1] + %1 = fpext float %0 to double ; [#uses=1] + %2 = load float* %x, align 4 ; [#uses=1] + %3 = fpext float %2 to double ; [#uses=1] + %4 = frem double %3, %1 ; [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} -- 2.34.1