Skip to content

Commit

Permalink
Replaces checked_fptosi/checked_fptoui intrinsics with Julia implemen…
Browse files Browse the repository at this point in the history
…tations. Fixes #14549.
  • Loading branch information
simonbyrne committed Jan 22, 2016
1 parent 1667a95 commit 9734e5d
Show file tree
Hide file tree
Showing 8 changed files with 22 additions and 98 deletions.
4 changes: 2 additions & 2 deletions base/boot.jl
Expand Up @@ -160,13 +160,13 @@ export
# intrinsics module
Intrinsics
#ccall, cglobal, llvmcall, abs_float, add_float, add_int, and_int, ashr_int,
#box, bswap_int, checked_fptosi, checked_fptoui,
#box, bswap_int,
#checked_sadd_int, checked_ssub_int, checked_smul_int, checked_sdiv_int,
#checked_srem_int, checked_uadd_int, checked_usub_int, checked_umul_int,
#checked_udiv_int, checked_urem_int,
#checked_trunc_sint, checked_trunc_uint, check_top_bit,
#nan_dom_err, copysign_float, ctlz_int, ctpop_int, cttz_int,
#div_float, eq_float, eq_int, eqfsi64, eqfui64, flipsign_int, select_value,
#div_float, eq_float, eq_int, flipsign_int, select_value,
#sqrt_llvm, powi_llvm,
#sqrt_llvm_fast,
#fpext, fpiseq, fpislt, fpsiround, fpuiround, fptosi, fptoui,
Expand Down
13 changes: 13 additions & 0 deletions base/float.jl
Expand Up @@ -165,6 +165,19 @@ function unsafe_trunc(::Type{Int128}, x::Float32)
copysign(unsafe_trunc(UInt128,x) % Int128, x)
end

# convert methods
@inline function convert{T<:Union{Int32,Int64,UInt32,UInt64},Tf<:Union{Float32,Float64}}(::Type{T}, x::Tf)
i = unsafe_trunc(T,x)
convert(Tf,i) == x || throw(InexactError())
i
end
# avoid undefined behaviour on ARM, cf #14549
@inline function convert{T<:Union{Int8,Int16,UInt8,UInt16},Tf<:Union{Float32,Float64}}(::Type{T}, x::Tf)
i = unsafe_trunc(Int32,x) % T
convert(Tf,i) == x || throw(InexactError())
i
end


# matches convert methods
# also determines floor, ceil, round
Expand Down
5 changes: 0 additions & 5 deletions base/int.jl
Expand Up @@ -204,11 +204,6 @@ rem{T<:Integer}(x::T, ::Type{T}) = x
rem(x::Integer, ::Type{Bool}) = ((x&1)!=0)
mod{T<:Integer}(x::Integer, ::Type{T}) = rem(x, T)

convert{T<:UnionS64Types,Tf<:Union{Float32,Float64}}(::Type{T}, x::Tf) =
box(T,checked_fptosi(T,unbox(Tf,x)))
convert{T<:UnionU64Types,Tf<:Union{Float32,Float64}}(::Type{T}, x::Tf) =
box(T,checked_fptoui(T,unbox(Tf,x)))

convert{T<:Union{Int128,UInt128},Tf<:Union{Float32,Float64}}(::Type{T},x::Tf) =
(isinteger(x) || throw(InexactError()) ; trunc(T,x))

Expand Down
78 changes: 0 additions & 78 deletions src/intrinsics.cpp
Expand Up @@ -621,80 +621,6 @@ static jl_cgval_t generic_zext(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ct
return mark_julia_type(ans, false, jlto);
}

static Value *emit_eqfsi(Value *x, Value *y)
{
Value *fy = JL_INT(y);

// using all 64-bit is slightly faster than using mixed sizes
Value *xx = x, *vv = fy;
if (x->getType() == T_float32)
xx = builder.CreateFPExt(xx, T_float64);
if (vv->getType()->getPrimitiveSizeInBits() < 64)
vv = builder.CreateSExt(vv, T_int64);

Value *back = builder.CreateSIToFP(vv, xx->getType());
return builder.CreateAnd
(builder.CreateFCmpOEQ(xx, back),
builder.CreateICmpEQ(vv, builder.CreateFPToSI(back, vv->getType())));
}

static Value *emit_eqfui(Value *x, Value *y)
{
Value *fy = JL_INT(y);

// using all 64-bit is slightly faster than using mixed sizes
Value *xx = x, *vv = fy;
if (x->getType() == T_float32)
xx = builder.CreateFPExt(xx, T_float64);
if (vv->getType()->getPrimitiveSizeInBits() < 64)
vv = builder.CreateZExt(vv, T_int64);

Value *back = builder.CreateUIToFP(vv, xx->getType());
return builder.CreateAnd
(builder.CreateFCmpOEQ(xx, back),
builder.CreateICmpEQ(vv, builder.CreateFPToUI(back, vv->getType())));
}

static jl_cgval_t emit_checked_fptosi(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx)
{
jl_value_t *jlto = staticeval_bitstype(targ, "checked_fptosi", ctx);
if (!jlto) return jl_cgval_t();
Type *to = staticeval_bitstype(jlto);
Value *fx = FP(auto_unbox(x, ctx));
if (fx->getType() == T_void) return jl_cgval_t(); // auto_unbox threw an error
Value *ans = builder.CreateFPToSI(fx, to);
if (fx->getType() == T_float32 && to == T_int32) {
raise_exception_unless
(builder.CreateFCmpOEQ(builder.CreateFPExt(fx, T_float64),
builder.CreateSIToFP(ans, T_float64)),
prepare_global(jlinexacterr_var), ctx);
}
else {
raise_exception_unless(emit_eqfsi(fx, ans), prepare_global(jlinexacterr_var), ctx);
}
return mark_julia_type(ans, false, jlto);
}

static jl_cgval_t emit_checked_fptoui(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx)
{
jl_value_t *jlto = staticeval_bitstype(targ, "checked_fptoui", ctx);
if (!jlto) return jl_cgval_t();
Type *to = staticeval_bitstype(jlto);
Value *fx = FP(auto_unbox(x, ctx));
if (fx->getType() == T_void) return jl_cgval_t(); // auto_unbox threw an error
Value *ans = builder.CreateFPToUI(fx, to);
if (fx->getType() == T_float32 && to == T_int32) {
raise_exception_unless
(builder.CreateFCmpOEQ(builder.CreateFPExt(fx, T_float64),
builder.CreateUIToFP(ans, T_float64)),
prepare_global(jlinexacterr_var), ctx);
}
else {
raise_exception_unless(emit_eqfui(fx, ans), prepare_global(jlinexacterr_var), ctx);
}
return mark_julia_type(ans, false, jlto);
}

static jl_cgval_t emit_runtime_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx)
{
int ldepth = ctx->gc.argDepth;
Expand Down Expand Up @@ -958,10 +884,6 @@ static jl_cgval_t emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs,
return generic_sext(args[1], args[2], ctx);
case zext_int:
return generic_zext(args[1], args[2], ctx);
case checked_fptosi:
return emit_checked_fptosi(args[1], args[2], ctx);
case checked_fptoui:
return emit_checked_fptoui(args[1], args[2], ctx);

case uitofp: {
jl_value_t *bt = staticeval_bitstype(args[1], "uitofp", ctx);
Expand Down
2 changes: 0 additions & 2 deletions src/intrinsics.h
Expand Up @@ -68,8 +68,6 @@
ADD_I(fptrunc, 2) \
ADD_I(fpext, 2) \
/* checked conversion */ \
ADD_I(checked_fptosi, 2) \
ADD_I(checked_fptoui, 2) \
ADD_I(checked_trunc_sint, 2) \
ADD_I(checked_trunc_uint, 2) \
ADD_I(check_top_bit, 1) \
Expand Down
2 changes: 0 additions & 2 deletions src/julia_internal.h
Expand Up @@ -403,8 +403,6 @@ JL_DLLEXPORT jl_value_t *jl_fpext(jl_value_t *ty, jl_value_t *a);
JL_DLLEXPORT jl_value_t *jl_fptoui_auto(jl_value_t *a);
JL_DLLEXPORT jl_value_t *jl_fptosi_auto(jl_value_t *a);

JL_DLLEXPORT jl_value_t *jl_checked_fptoui(jl_value_t *ty, jl_value_t *a);
JL_DLLEXPORT jl_value_t *jl_checked_fptosi(jl_value_t *ty, jl_value_t *a);
JL_DLLEXPORT jl_value_t *jl_checked_trunc_sint(jl_value_t *ty, jl_value_t *a);
JL_DLLEXPORT jl_value_t *jl_checked_trunc_uint(jl_value_t *ty, jl_value_t *a);

Expand Down
9 changes: 0 additions & 9 deletions src/runtime_intrinsics.c
Expand Up @@ -818,15 +818,6 @@ static unsigned check_trunc_uint(unsigned isize, unsigned osize, void *pa)
}
cvt_iintrinsic_checked(LLVMTrunc, check_trunc_uint, checked_trunc_uint)

#define checked_fptosi(pr, a) \
if (!LLVMFPtoSI_exact(sizeof(a) * host_char_bit, pa, osize, pr)) \
jl_throw(jl_inexact_exception);
un_fintrinsic_withtype(checked_fptosi, checked_fptosi)
#define checked_fptoui(pr, a) \
if (!LLVMFPtoUI_exact(sizeof(a) * host_char_bit, pa, osize, pr)) \
jl_throw(jl_inexact_exception);
un_fintrinsic_withtype(checked_fptoui, checked_fptoui)

JL_DLLEXPORT jl_value_t *jl_check_top_bit(jl_value_t *a)
{
jl_value_t *ty = jl_typeof(a);
Expand Down
7 changes: 7 additions & 0 deletions test/numbers.jl
Expand Up @@ -2562,6 +2562,13 @@ end
@test_throws InexactError convert(Int16, typemax(UInt64))
@test_throws InexactError convert(Int, typemax(UInt64))

# issue #14549
for T in (Int8, Int16, UInt8, UInt16)
for F in (Float32,Float64)
@test_throws InexactError convert(T, F(200000.0))
end
end

let x = big(-0.0)
@test signbit(x) && !signbit(abs(x))
end
Expand Down

0 comments on commit 9734e5d

Please sign in to comment.