From bde8f790dc89de225c256669a747816b09c1817c Mon Sep 17 00:00:00 2001 From: "Arch D. Robison" Date: Fri, 12 Sep 2014 17:40:33 -0500 Subject: [PATCH] Add LLVM intrinsics for floor/ceil/trunc/abs. Add tests for vector trunc, round, floor, ceil. Add fast algorithm for round. --- base/float.jl | 7 +++++-- base/math.jl | 19 +++++++++++++++---- src/intrinsics.cpp | 28 ++++++++++++++++++++++++++-- test/numbers.jl | 15 +++++++++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/base/float.jl b/base/float.jl index ed11352cdcda0..127191fffa6e4 100644 --- a/base/float.jl +++ b/base/float.jl @@ -168,8 +168,11 @@ round {T<:Integer}(::Type{T}, x::FloatingPoint) = trunc(T,round(x)) # this is needed very early because it is used by Range and colon -round(x::Float64) = ccall((:round, Base.libm_name), Float64, (Float64,), x) -floor(x::Float64) = ccall((:floor, Base.libm_name), Float64, (Float64,), x) +function round(x::Float64) + y = trunc(x) + ifelse(x==y,y,trunc(2.0*x-y)) +end +floor(x::Float64) = box(Float64,floor_llvm(unbox(Float64,x))) ## floating point promotions ## promote_rule(::Type{Float32}, ::Type{Float16}) = Float32 diff --git a/base/math.jl b/base/math.jl index 9094aa0d3bbbd..3e374cf8161ad 100644 --- a/base/math.jl +++ b/base/math.jl @@ -25,7 +25,7 @@ import Base: log, exp, sin, cos, tan, sinh, cosh, tanh, asin, max, min, minmax, ceil, floor, trunc, round, ^, exp2, exp10, expm1, log1p -import Core.Intrinsics: nan_dom_err, sqrt_llvm, box, unbox, powi_llvm +import Core.Intrinsics: nan_dom_err, ceil_llvm, floor_llvm, trunc_llvm, sqrt_llvm, box, unbox, powi_llvm # non-type specific math functions @@ -132,7 +132,15 @@ sqrt(x::Float32) = box(Float32,sqrt_llvm(unbox(Float32,x))) sqrt(x::Real) = sqrt(float(x)) @vectorize_1arg Number sqrt -for f in (:ceil, :trunc, :significand, :rint) # :nearbyint +ceil(x::Float64) = box(Float64,ceil_llvm(unbox(Float64,x))) +ceil(x::Float32) = box(Float32,ceil_llvm(unbox(Float32,x))) +@vectorize_1arg Real ceil + +trunc(x::Float64) = box(Float64,trunc_llvm(unbox(Float64,x))) +trunc(x::Float32) = box(Float32,trunc_llvm(unbox(Float32,x))) +@vectorize_1arg Real trunc + +for f in (:significand, :rint) # :nearbyint @eval begin ($f)(x::Float64) = ccall(($(string(f)),libm), Float64, (Float64,), x) ($f)(x::Float32) = ccall(($(string(f,"f")),libm), Float32, (Float32,), x) @@ -140,10 +148,13 @@ for f in (:ceil, :trunc, :significand, :rint) # :nearbyint end end -round(x::Float32) = ccall((:roundf, libm), Float32, (Float32,), x) +function round(x::Float32) + y = trunc(x) + ifelse(x==y,y,trunc(2.f0*x-y)) +end @vectorize_1arg Real round -floor(x::Float32) = ccall((:floorf, libm), Float32, (Float32,), x) +floor(x::Float32) = box(Float32,floor_llvm(unbox(Float32,x))) @vectorize_1arg Real floor hypot(x::Real, y::Real) = hypot(promote(float(x), float(y))...) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index af69094d14b0b..a857a1ae3ae70 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -29,7 +29,7 @@ namespace JL_I { nan_dom_err, // functions abs_float, copysign_float, flipsign_int, select_value, - sqrt_llvm, powi_llvm, + ceil_llvm, floor_llvm, trunc_llvm, sqrt_llvm, powi_llvm, // pointer access pointerref, pointerset, pointertoref, // c interface @@ -1099,12 +1099,18 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, HANDLE(abs_float,1) { x = FP(x); +#ifdef LLVM34 + return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::fabs, + ArrayRef(x->getType())), + x); +#else Type *intt = JL_INTT(x->getType()); Value *bits = builder.CreateBitCast(FP(x), intt); Value *absbits = builder.CreateAnd(bits, ConstantInt::get(intt, APInt::getSignedMaxValue(((IntegerType*)intt)->getBitWidth()))); return builder.CreateBitCast(absbits, x->getType()); +#endif } HANDLE(copysign_float,2) { @@ -1147,6 +1153,24 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, HANDLE(jl_alloca,1) { return builder.CreateAlloca(IntegerType::get(jl_LLVMContext, 8),JL_INT(x)); } + HANDLE(ceil_llvm,1) { + x = FP(x); + return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::ceil, + ArrayRef(x->getType())), + x); + } + HANDLE(floor_llvm,1) { + x = FP(x); + return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::floor, + ArrayRef(x->getType())), + x); + } + HANDLE(trunc_llvm,1) { + x = FP(x); + return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::trunc, + ArrayRef(x->getType())), + x); + } HANDLE(sqrt_llvm,1) { x = FP(x); raise_exception_unless(builder.CreateFCmpUGE(x, ConstantFP::get(x->getType(),0.0)), @@ -1245,7 +1269,7 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(uitofp); ADD_I(sitofp); ADD_I(fptrunc); ADD_I(fpext); ADD_I(abs_float); ADD_I(copysign_float); - ADD_I(flipsign_int); ADD_I(select_value); ADD_I(sqrt_llvm); + ADD_I(flipsign_int); ADD_I(select_value); ADD_I(ceil_llvm); ADD_I(floor_llvm); ADD_I(trunc_llvm); ADD_I(sqrt_llvm); ADD_I(powi_llvm); ADD_I(pointerref); ADD_I(pointerset); ADD_I(pointertoref); ADD_I(checked_sadd); ADD_I(checked_uadd); diff --git a/test/numbers.jl b/test/numbers.jl index 9415304630fdc..0b68f373faf0d 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1330,6 +1330,21 @@ for x = 2^24-10:2^24+10 @test ceil(Int,y) == i end +# rounding vectors +let ≈(x,y) = x==y && typeof(x)==typeof(y) + for t in [Float32,Float64] + # try different vector lengths + for n in [0,3,255,256] + r = (1:n)-div(n,2) + y = t[x/4 for x in r] + @test trunc(y) ≈ t[div(i,4) for i in r] + @test round(y) ≈ t[(i+1+(i>=0))>>2 for i in r] + @test floor(y) ≈ t[i>>2 for i in r] + @test ceil(y) ≈ t[(i+3)>>2 for i in r] + end + end +end + @test_throws InexactError round(Int,Inf) @test_throws InexactError round(Int,NaN) @test round(Int,2.5) == 3