aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ADT/APFloat.h1
-rw-r--r--lib/Support/APFloat.cpp86
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp10
-rw-r--r--lib/VMCore/ConstantFold.cpp10
-rw-r--r--test/Transforms/InstCombine/2009-01-19-fmod-constant-float-specials.ll315
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
+}