diff options
-rw-r--r-- | include/llvm/ADT/APFloat.h | 1 | ||||
-rw-r--r-- | lib/Support/APFloat.cpp | 86 | ||||
-rw-r--r-- | lib/Transforms/Scalar/InstructionCombining.cpp | 10 | ||||
-rw-r--r-- | lib/VMCore/ConstantFold.cpp | 10 | ||||
-rw-r--r-- | test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll | 315 |
5 files changed, 384 insertions, 38 deletions
diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 5b09d48..29a89dd 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 151f9d5..c296770 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 c02fabd..f038cd0 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<Constant>(Op0)) - if (LHS->isNullValue()) - return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); - if (isa<UndefValue>(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<Constant>(Op0)) + if (LHS->isNullValue()) + return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); + if (ConstantInt *RHS = dyn_cast<ConstantInt>(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 0c5297f..5c1578f 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<double>:: - quiet_NaN())); - if (CFP1->getType() == Type::FloatTy) - return ConstantFP::get(APFloat(std::numeric_limits<float>:: - 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 0000000..fdcafca --- /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 ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store float 0x7FF0000000000000, float* %x, align 4 + store float 0x7FF8000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +declare i32 @printf(i8*, ...) nounwind + +define void @foo2() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo3() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo4() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store float 0x7FF0000000000000, float* %x, align 4 + store float 0x7FF0000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo5() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store float 0x7FF8000000000000, float* %x, align 4 + store float 0x7FF0000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo6() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo7() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo8() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0] + store float 0x7FF8000000000000, float* %x, align 4 + store float 0x7FF8000000000000, float* %y, align 4 + %0 = load float* %y, align 4 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo9() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo10() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo11() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo12() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo13() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo14() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo15() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +define void @foo16() nounwind { +entry: + %y = alloca float ; <float*> [#uses=2] + %x = alloca float ; <float*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; <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 ; <float> [#uses=1] + %1 = fpext float %0 to double ; <double> [#uses=1] + %2 = load float* %x, align 4 ; <float> [#uses=1] + %3 = fpext float %2 to double ; <double> [#uses=1] + %4 = frem double %3, %1 ; <double> [#uses=1] + %5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @"\01LC", i32 0, i32 0), double %4) nounwind ; <i32> [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} |