From ca1c1df7b65d86a00d115c9f6ae23986c8bf4107 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 29 Jun 2013 03:41:40 -0400 Subject: [PATCH] Generialize float intrinsics Add support for FLoat16 --- base/boot.jl | 4 +- base/exports.jl | 1 + base/float.jl | 83 ++++++++++------------------------ base/io.jl | 5 ++- src/cgutils.cpp | 25 +++++------ src/codegen.cpp | 15 ++++--- src/init.c | 1 + src/intrinsics.cpp | 108 ++++++++++++++++++++++----------------------- src/jltypes.c | 1 + src/julia.h | 3 ++ 10 files changed, 110 insertions(+), 136 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 28896a2b41d0c..228138d781cae 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -154,8 +154,8 @@ export #fptrunc32, le_float, lefsi64, lefui64, lesif64, #leuif64, lshr_int, lt_float, ltfsi64, ltfui64, ltsif64, ltuif64, mul_float, #mul_int, ne_float, ne_int, neg_float, neg_int, not_int, or_int, rem_float, - #sdiv_int, shl_int, sitofp32, sitofp64, sle_int, slt_int, smod_int, - #srem_int, sub_float, sub_int, trunc_int, udiv_int, uitofp32, uitofp64, + #sdiv_int, shl_int, sitofp, sle_int, slt_int, smod_int, + #srem_int, sub_float, sub_int, trunc_int, udiv_int, uitofp, #ule_int, ult_int, unbox, urem_int, xor_int, sext_int, zext_int diff --git a/base/exports.jl b/base/exports.jl index 6c7fbd5db1b4d..0f0de5c98af14 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -328,6 +328,7 @@ export fld, flipsign, float, + float16, float32, float64, floor, diff --git a/base/float.jl b/base/float.jl index 7c3cfc6fa70b3..3eace2e95302e 100644 --- a/base/float.jl +++ b/base/float.jl @@ -1,32 +1,24 @@ +bitstype 16 Float16 <: FloatingPoint ## conversions to floating-point ## -convert(::Type{Float32}, x::Bool) = box(Float32,uitofp32(unbox(Bool,x))) -convert(::Type{Float32}, x::Char) = box(Float32,uitofp32(unbox(Float32,x))) -convert(::Type{Float32}, x::Int8) = box(Float32,sitofp32(unbox(Int8,x))) -convert(::Type{Float32}, x::Int16) = box(Float32,sitofp32(unbox(Int16,x))) -convert(::Type{Float32}, x::Int32) = box(Float32,sitofp32(unbox(Int32,x))) -convert(::Type{Float32}, x::Int64) = box(Float32,sitofp32(unbox(Int64,x))) -convert(::Type{Float32}, x::Int128) = float32(uint128(abs(x)))*(1-2(x<0)) -convert(::Type{Float32}, x::Uint8) = box(Float32,uitofp32(unbox(Uint8,x))) -convert(::Type{Float32}, x::Uint16) = box(Float32,uitofp32(unbox(Uint16,x))) -convert(::Type{Float32}, x::Uint32) = box(Float32,uitofp32(unbox(Uint32,x))) -convert(::Type{Float32}, x::Uint64) = box(Float32,uitofp32(unbox(Uint64,x))) -convert(::Type{Float32}, x::Uint128) = float32(uint64(x)) + ldexp(float32(uint64(x>>>64)),64) -convert(::Type{Float32}, x::Float64) = box(Float32,fptrunc32(unbox(Float64,x))) - -convert(::Type{Float64}, x::Bool) = box(Float64,uitofp64(unbox(Bool,x))) -convert(::Type{Float64}, x::Char) = box(Float64,uitofp64(unbox(Char,x))) -convert(::Type{Float64}, x::Int8) = box(Float64,sitofp64(unbox(Int8,x))) -convert(::Type{Float64}, x::Int16) = box(Float64,sitofp64(unbox(Int16,x))) -convert(::Type{Float64}, x::Int32) = box(Float64,sitofp64(unbox(Int32,x))) -convert(::Type{Float64}, x::Int64) = box(Float64,sitofp64(unbox(Int64,x))) -convert(::Type{Float64}, x::Int128) = float64(uint128(abs(x)))*(1-2(x<0)) -convert(::Type{Float64}, x::Uint8) = box(Float64,uitofp64(unbox(Uint8,x))) -convert(::Type{Float64}, x::Uint16) = box(Float64,uitofp64(unbox(Uint16,x))) -convert(::Type{Float64}, x::Uint32) = box(Float64,uitofp64(unbox(Uint32,x))) -convert(::Type{Float64}, x::Uint64) = box(Float64,uitofp64(unbox(Uint64,x))) -convert(::Type{Float64}, x::Uint128) = float64(uint64(x)) + ldexp(float64(uint64(x>>>64)),64) -convert(::Type{Float64}, x::Float32) = box(Float64,fpext64(unbox(Float32,x))) +for t1 in (Float16,Float32,Float64) + for st in (Int8,Int16,Int32,Int64,Int128) + @eval begin + convert(::Type{$t1},x::($st)) = box($t1,sitofp(unbox($st,x),$t1)) + promote_rule(::Type{$t1}, ::Type{$st} ) = $t1 + end + end + for ut in (Bool,Char,Uint8,Uint16,Uint32,Uint64,Uint128) + @eval begin + convert(::Type{$t1},x::($ut)) = box($t1,uitofp(unbox($ut,x),$t1)) + promote_rule(::Type{$t1}, ::Type{$ut} ) = $t1 + end + end +end +convert(::Type{Float16}, x::Union(Float32,Float64)) = box(Float16,fptrunc(x,Float16)) +convert(::Type{Float32}, x::Float16) = box(Float32,fpext(x,Float32)) +convert(::Type{Float32}, x::Float64) = box(Float32,fptrunc(x,Float32)) +convert(::Type{Float64}, x::Union(Float32,Float16)) = box(Float64,fpext(x,Float64)) convert(::Type{FloatingPoint}, x::Bool) = convert(Float32, x) convert(::Type{FloatingPoint}, x::Char) = convert(Float32, x) @@ -41,6 +33,7 @@ convert(::Type{FloatingPoint}, x::Uint32) = convert(Float64, x) convert(::Type{FloatingPoint}, x::Uint64) = convert(Float64, x) # LOSSY convert(::Type{FloatingPoint}, x::Uint128) = convert(Float64, x) # LOSSY +float16(x) = convert(Float16, x) float32(x) = convert(Float32, x) float64(x) = convert(Float64, x) float(x) = convert(FloatingPoint, x) @@ -83,9 +76,9 @@ iround(::Type{Int32}, x::Float32) = box(Int32,fpsiround(unbox(Float32,x))) iround(::Type{Int32}, x::Float64) = box(Int32,trunc_int(Int32,fpsiround(unbox(Float64,x)))) iround(::Type{Uint32}, x::Float32) = box(Uint32,fpuiround(unbox(Float32,x))) iround(::Type{Uint32}, x::Float64) = box(Uint32,trunc_int(Uint32,fpuiround(unbox(Float64,x)))) -iround(::Type{Int64}, x::Float32) = box(Int64,fpsiround(fpext64(unbox(Float32,x)))) +iround(::Type{Int64}, x::Float32) = box(Int64,fpsiround(float64(x))) iround(::Type{Int64}, x::Float64) = box(Int64,fpsiround(unbox(Float64,x))) -iround(::Type{Uint64}, x::Float32) = box(Uint64,fpuiround(fpext64(unbox(Float32,x)))) +iround(::Type{Uint64}, x::Float32) = box(Uint64,fpuiround(float64(x))) iround(::Type{Uint64}, x::Float64) = box(Uint64,fpuiround(unbox(Float64,x))) iround(::Type{Int128}, x::Float32) = convert(Int128,round(x)) @@ -99,35 +92,10 @@ floor(x::Float64) = ccall((:floor, Base.libm_name), Float64, (Float64,), x) ## floating point promotions ## +promote_rule(::Type{Float32}, ::Type{Float16}) = Float32 promote_rule(::Type{Float64}, ::Type{Float32}) = Float64 -promote_rule(::Type{Float32}, ::Type{Int8} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Int16} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Int32} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Int64} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Int128}) = Float32 - -promote_rule(::Type{Float64}, ::Type{Int8} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Int16} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Int32} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Int64} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Int128}) = Float64 - -promote_rule(::Type{Float32}, ::Type{Uint8} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Uint16} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Uint32} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Uint64} ) = Float32 -promote_rule(::Type{Float32}, ::Type{Uint128}) = Float32 - -promote_rule(::Type{Float64}, ::Type{Uint8} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Uint16} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Uint32} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Uint64} ) = Float64 -promote_rule(::Type{Float64}, ::Type{Uint128}) = Float64 - -promote_rule(::Type{Float32}, ::Type{Char}) = Float32 -promote_rule(::Type{Float64}, ::Type{Char}) = Float64 - +morebits(::Type{Float16}) = Float32 morebits(::Type{Float32}) = Float64 ## floating point arithmetic ## @@ -260,9 +228,6 @@ const NaN = box(Float64,unbox(Uint64,0x7ff8000000000000)) eps() = eps(Float64) end -sizeof(::Type{Float32}) = 4 -sizeof(::Type{Float64}) = 8 - ## byte order swaps for arbitrary-endianness serialization/deserialization ## bswap(x::Float32) = box(Float32,bswap_int(unbox(Float32,x))) bswap(x::Float64) = box(Float64,bswap_int(unbox(Float64,x))) diff --git a/base/io.jl b/base/io.jl index 6507c5704a2d6..38f4efc70d63c 100644 --- a/base/io.jl +++ b/base/io.jl @@ -46,8 +46,9 @@ else end write(s::IO, x::Bool) = write(s, uint8(x)) -write(s::IO, x::Float32) = write(s, box(Int32,unbox(Float32,x))) -write(s::IO, x::Float64) = write(s, box(Int64,unbox(Float64,x))) +write(s::IO, x::Float16) = write(s, reinterpret(Int16,x)) +write(s::IO, x::Float32) = write(s, reinterpret(Int32,x)) +write(s::IO, x::Float64) = write(s, reinterpret(Int64,x)) function write(s::IO, a::AbstractArray) nb = 0 diff --git a/src/cgutils.cpp b/src/cgutils.cpp index c41576a228b49..1a0d813d36fd0 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -65,8 +65,6 @@ static Type *julia_struct_to_llvm(jl_value_t *jt); static Type *julia_type_to_llvm(jl_value_t *jt) { if (jt == (jl_value_t*)jl_bool_type) return T_int1; - if (jt == (jl_value_t*)jl_float32_type) return T_float32; - if (jt == (jl_value_t*)jl_float64_type) return T_float64; if (jt == (jl_value_t*)jl_bottom_type) return T_void; if (!jl_is_leaf_type(jt)) return jl_pvalue_llvmt; @@ -79,12 +77,18 @@ static Type *julia_type_to_llvm(jl_value_t *jt) return PointerType::get(lt, 0); } if (jl_is_bitstype(jt)) { - int nb = jl_datatype_size(jt)*8; - if (nb == 8) return T_int8; - if (nb == 16) return T_int16; - if (nb == 32) return T_int32; - if (nb == 64) return T_int64; - else return Type::getIntNTy(getGlobalContext(), nb); + int nb = jl_datatype_size(jt); + if(jl_is_floattype(jt)) { + if(nb == 2) + return Type::getHalfTy(jl_LLVMContext); + else if(nb == 4) + return Type::getFloatTy(jl_LLVMContext); + else if(nb == 8) + return Type::getDoubleTy(jl_LLVMContext); + else if(nb == 16) + return Type::getFP128Ty(jl_LLVMContext); + } + return Type::getIntNTy(jl_LLVMContext, nb*8); } if (jl_isbits(jt)) { if (((jl_datatype_t*)jt)->size == 0) { @@ -245,11 +249,6 @@ static Value *mark_julia_type(Value *v, jl_value_t *jt) return v; } -static Value *mark_julia_type(Value *v, jl_datatype_t *jt) -{ - return mark_julia_type(v, (jl_value_t*)jt); -} - // --- generating various error checks --- static jl_value_t *llvm_type_to_julia(Type *t, bool err=true); diff --git a/src/codegen.cpp b/src/codegen.cpp index 976fe22fe26b6..a0dd8e8082c17 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -142,7 +142,7 @@ static Value *V_null; static GlobalVariable *jltrue_var; static GlobalVariable *jlfalse_var; static GlobalVariable *jlnull_var; -static GlobalVariable *jlfloat32temp_var; +static GlobalVariable *jlfloattemp_var; #ifdef JL_GC_MARKSWEEP static GlobalVariable *jlpgcstack_var; #endif @@ -247,7 +247,7 @@ static Function *to_function(jl_lambda_info_t *li, bool cstyle) assert(f != NULL); nested_compile = last_n_c; //f->dump(); - //verifyFunction(*f); + verifyFunction(*f); FPM->run(*f); //n_compile++; // print out the function's LLVM code @@ -2953,10 +2953,13 @@ static void init_julia_llvm_env(Module *m) (void*)&jl_inexact_exception); jlboundserr_var = global_to_llvm("jl_bounds_exception", (void*)&jl_bounds_exception); - jlfloat32temp_var = - new GlobalVariable(*jl_Module, T_float32, - false, GlobalVariable::PrivateLinkage, - ConstantFP::get(T_float32,0.0), "jl_float32_temp"); + + // Has to be big enough for the biggest LLVM-supported float type + jlfloattemp_var = + new GlobalVariable(*jl_Module, IntegerType::get(jl_LLVMContext,128), + false, GlobalVariable::PrivateLinkage, + ConstantInt::get(IntegerType::get(jl_LLVMContext,128),0), + "jl_float_temp"); std::vector args1(0); args1.push_back(T_pint8); diff --git a/src/init.c b/src/init.c index 842209a608c54..90fc8ceb7d639 100644 --- a/src/init.c +++ b/src/init.c @@ -684,6 +684,7 @@ void jl_get_builtin_hooks(void) jl_float32_type = (jl_datatype_t*)core("Float32"); jl_float64_type = (jl_datatype_t*)core("Float64"); + jl_floatingpoint_type = (jl_datatype_t*)core("FloatingPoint"); jl_stackovf_exception = jl_apply((jl_function_t*)core("StackOverflowError"), NULL, 0); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 14030c9634354..b69e509796e38 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -24,8 +24,8 @@ namespace JL_I { bswap_int, ctpop_int, ctlz_int, cttz_int, // conversion sext_int, zext_int, trunc_int, - fptoui, fptosi, uitofp32, sitofp32, uitofp64, sitofp64, - fptrunc32, fpext64, + fptoui, fptosi, uitofp, sitofp, + fptrunc, fpext, // checked conversion fpsiround, fpuiround, checked_fptoui, checked_fptosi, // checked arithmetic @@ -57,14 +57,25 @@ using namespace JL_I; where the box is needed. */ +static Type *FTnbits(size_t nb) +{ + if(nb == 16) + return Type::getHalfTy(jl_LLVMContext); + else if(nb == 32) + return Type::getFloatTy(jl_LLVMContext); + else if(nb == 64) + return Type::getDoubleTy(jl_LLVMContext); + else if(nb == 128) + return Type::getFP128Ty(jl_LLVMContext); + else + jl_error("Unsupported Float Size"); +} // convert int type to same-size float type static Type *FT(Type *t) { if (t->isFloatingPointTy()) return t; - if (t == T_int32) return T_float32; - assert(t == T_int64); - return T_float64; + return FTnbits(t->getPrimitiveSizeInBits()); } // reinterpret-cast to float @@ -109,24 +120,7 @@ static Value *uint_cnvt(Type *to, Value *x) static Value *emit_unboxed(jl_value_t *e, jl_codectx_t *ctx) { - if (jl_is_int32(e)) { - return ConstantInt::get(T_int32, jl_unbox_int32(e)); - } - else if (jl_is_int64(e)) { - return ConstantInt::get(T_int64, jl_unbox_int64(e)); - } - else if (jl_is_uint64(e)) { - return mark_julia_type(ConstantInt::get(T_int64, - (int64_t)jl_unbox_uint64(e)), - jl_uint64_type); - } - else if (jl_is_float64(e)) { - return ConstantFP::get(T_float64, jl_unbox_float64(e)); - } - else if (jl_is_float32(e)) { - return ConstantFP::get(T_float32, jl_unbox_float32(e)); - } - else if (e == jl_true) { + if (e == jl_true) { return ConstantInt::get(T_int1, 1); } else if (e == jl_false) { @@ -135,19 +129,26 @@ static Value *emit_unboxed(jl_value_t *e, jl_codectx_t *ctx) else if (jl_is_bitstype(jl_typeof(e))) { jl_datatype_t *bt = (jl_datatype_t*)jl_typeof(e); int nb = jl_datatype_size(bt); - if (nb == 1) - return mark_julia_type(ConstantInt::get(T_int8, jl_unbox_int8(e)), - (jl_value_t*)bt); - if (nb == 2) - return mark_julia_type(ConstantInt::get(T_int16, jl_unbox_int16(e)), - (jl_value_t*)bt); - if (nb == 4) - return mark_julia_type(ConstantInt::get(T_int32, jl_unbox_int32(e)), - (jl_value_t*)bt); - if (nb == 8) - return mark_julia_type(ConstantInt::get(T_int64, jl_unbox_int64(e)), - (jl_value_t*)bt); - // TODO: bigger sizes + //APInt copies the data (but only as much as needed, so it doesn't matter if ArrayRef extends too far) + APInt val = APInt(8*nb,ArrayRef((uint64_t*)jl_data_ptr(e),(nb+7)/8)); + if(jl_is_float(e)) + { +#ifdef LLVM33 + #define LLVM_FP(a,b) APFloat(a,b) +#else + #define LLVM_FP(a,b) APFloat(b,true) +#endif + if(nb == 2) + return mark_julia_type(ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEhalf,val)),(jl_value_t*)bt); + else if(nb == 4) + return mark_julia_type(ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEfloat,val)),(jl_value_t*)bt); + else if(nb == 8) + return mark_julia_type(ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEdouble,val)),(jl_value_t*)bt); + else if(nb == 16) + return mark_julia_type(ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEquad,val)),(jl_value_t*)bt); + // If we have a floating point type that's not hardware supported, just treat it like an integer for LLVM purposes + } + return mark_julia_type(ConstantInt::get(IntegerType::get(jl_LLVMContext,8*nb),val),(jl_value_t*)bt); } return emit_expr(e, ctx, false); } @@ -608,6 +609,21 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, Value *x = FP(auto_unbox(args[2], ctx)); return emit_checked_fptoui(args[1], x, ctx); } + HANDLE(uitofp,2) return builder.CreateUIToFP(JL_INT(auto_unbox(args[1],ctx)), FTnbits(try_to_determine_bitstype_nbits(args[2],ctx))); + HANDLE(sitofp,2) return builder.CreateSIToFP(JL_INT(auto_unbox(args[1],ctx)), FTnbits(try_to_determine_bitstype_nbits(args[2],ctx))); + HANDLE(fptrunc,2) return builder.CreateFPTrunc(FP(auto_unbox(args[1],ctx)), FTnbits(try_to_determine_bitstype_nbits(args[2],ctx))); + HANDLE(fpext,2) { + // when extending a float32 to a float64, we need to force + // rounding to single precision first. the reason is that it's + // fine to keep working in extended precision as long as it's + // understood that everything is implicitly rounded to 23 bits, + // but if we start looking at more bits we need to actually do the + // rounding first instead of carrying around incorrect low bits. + Value *x = auto_unbox(args[1],ctx); + builder.CreateStore(FP(x), builder.CreateBitCast(jlfloattemp_var,FT(x->getType())->getPointerTo()), true); + return builder.CreateFPExt(builder.CreateLoad(builder.CreateBitCast(jlfloattemp_var,FT(x->getType())->getPointerTo()), true), + FTnbits(try_to_determine_bitstype_nbits(args[2],ctx))); + } default: ; } @@ -945,22 +961,6 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, { return emit_iround(x, f == fpsiround, ctx); } - HANDLE(uitofp32,1) return builder.CreateUIToFP(JL_INT(x), T_float32); - HANDLE(sitofp32,1) return builder.CreateSIToFP(JL_INT(x), T_float32); - HANDLE(uitofp64,1) return builder.CreateUIToFP(JL_INT(x), T_float64); - HANDLE(sitofp64,1) return builder.CreateSIToFP(JL_INT(x), T_float64); - HANDLE(fptrunc32,1) return builder.CreateFPTrunc(FP(x), T_float32); - HANDLE(fpext64,1) - // when extending a float32 to a float64, we need to force - // rounding to single precision first. the reason is that it's - // fine to keep working in extended precision as long as it's - // understood that everything is implicitly rounded to 23 bits, - // but if we start looking at more bits we need to actually do the - // rounding first instead of carrying around incorrect low bits. - builder.CreateStore(FP(x), jlfloat32temp_var, true); - return builder.CreateFPExt(builder.CreateLoad(jlfloat32temp_var, true), - T_float64); - HANDLE(nan_dom_err,2) { // nan_dom_err(f, x) throw DomainError if isnan(f)&&!isnan(x) Value *f = FP(x); x = FP(y); @@ -1096,8 +1096,8 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(sext_int); ADD_I(zext_int); ADD_I(trunc_int); ADD_I(fptoui); ADD_I(fptosi); ADD_I(fpsiround); ADD_I(fpuiround); - ADD_I(uitofp32); ADD_I(sitofp32); ADD_I(uitofp64); ADD_I(sitofp64); - ADD_I(fptrunc32); ADD_I(fpext64); + 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(pointerref); ADD_I(pointerset); ADD_I(pointertoref); diff --git a/src/jltypes.c b/src/jltypes.c index febce5feacbc0..22ab1570416e3 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -45,6 +45,7 @@ jl_datatype_t *jl_int64_type; jl_datatype_t *jl_uint64_type; jl_datatype_t *jl_float32_type; jl_datatype_t *jl_float64_type; +jl_datatype_t *jl_floatingpoint_type; jl_tuple_t *jl_null; jl_value_t *jl_nothing; diff --git a/src/julia.h b/src/julia.h index 528a748a05ce7..e7a71e4cc4af3 100644 --- a/src/julia.h +++ b/src/julia.h @@ -383,6 +383,7 @@ extern jl_datatype_t *jl_int64_type; extern jl_datatype_t *jl_uint64_type; extern jl_datatype_t *jl_float32_type; extern jl_datatype_t *jl_float64_type; +extern jl_datatype_t *jl_floatingpoint_type; extern jl_datatype_t *jl_voidpointer_type; extern jl_datatype_t *jl_pointer_type; @@ -520,6 +521,8 @@ void *allocobj(size_t sz); #define jl_is_int64(v) jl_typeis(v,jl_int64_type) #define jl_is_uint32(v) jl_typeis(v,jl_uint32_type) #define jl_is_uint64(v) jl_typeis(v,jl_uint64_type) +#define jl_is_float(v) jl_subtype(v,(jl_value_t*)jl_floatingpoint_type,true) +#define jl_is_floattype(v) jl_subtype(v,(jl_value_t*)jl_floatingpoint_type,false) #define jl_is_float32(v) jl_typeis(v,jl_float32_type) #define jl_is_float64(v) jl_typeis(v,jl_float64_type) #define jl_is_bool(v) jl_typeis(v,jl_bool_type)