Skip to content

Commit

Permalink
Add LLVM intrinsics for floor/ceil/trunc/abs.
Browse files Browse the repository at this point in the history
Add tests for vector trunc, round, floor, ceil.
Add fast algorithm for round.
  • Loading branch information
Arch D. Robison committed Dec 8, 2014
1 parent ac92b48 commit bde8f79
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 8 deletions.
7 changes: 5 additions & 2 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 15 additions & 4 deletions base/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -132,18 +132,29 @@ 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)
@vectorize_1arg Real $f
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))...)
Expand Down
28 changes: 26 additions & 2 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<Type*>(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)
{
Expand Down Expand Up @@ -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<Type*>(x->getType())),
x);
}
HANDLE(floor_llvm,1) {
x = FP(x);
return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::floor,
ArrayRef<Type*>(x->getType())),
x);
}
HANDLE(trunc_llvm,1) {
x = FP(x);
return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::trunc,
ArrayRef<Type*>(x->getType())),
x);
}
HANDLE(sqrt_llvm,1) {
x = FP(x);
raise_exception_unless(builder.CreateFCmpUGE(x, ConstantFP::get(x->getType(),0.0)),
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bde8f79

Please sign in to comment.