diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f4530a2863386..d44c239c4706f 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2369,6 +2369,67 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { let frameaddress = decl_cdecl_fn(llmod, ~"llvm.frameaddress", T_fn(T_frameaddress_args, T_ptr(T_i8()))); + let sqrtf32 = decl_cdecl_fn(llmod, ~"llvm.sqrt.f32", + T_fn(~[T_f32()], T_f32())); + let sqrtf64 = decl_cdecl_fn(llmod, ~"llvm.sqrt.f64", + T_fn(~[T_f64()], T_f64())); + let powif32 = decl_cdecl_fn(llmod, ~"llvm.powi.f32", + T_fn(~[T_f32(), T_i32()], T_f32())); + let powif64 = decl_cdecl_fn(llmod, ~"llvm.powi.f64", + T_fn(~[T_f64(), T_i32()], T_f64())); + let sinf32 = decl_cdecl_fn(llmod, ~"llvm.sin.f32", + T_fn(~[T_f32()], T_f32())); + let sinf64 = decl_cdecl_fn(llmod, ~"llvm.sin.f64", + T_fn(~[T_f64()], T_f64())); + let cosf32 = decl_cdecl_fn(llmod, ~"llvm.cos.f32", + T_fn(~[T_f32()], T_f32())); + let cosf64 = decl_cdecl_fn(llmod, ~"llvm.cos.f64", + T_fn(~[T_f64()], T_f64())); + let powf32 = decl_cdecl_fn(llmod, ~"llvm.pow.f32", + T_fn(~[T_f32(), T_f32()], T_f32())); + let powf64 = decl_cdecl_fn(llmod, ~"llvm.pow.f64", + T_fn(~[T_f64(), T_f64()], T_f64())); + let expf32 = decl_cdecl_fn(llmod, ~"llvm.exp.f32", + T_fn(~[T_f32()], T_f32())); + let expf64 = decl_cdecl_fn(llmod, ~"llvm.exp.f64", + T_fn(~[T_f64()], T_f64())); + let exp2f32 = decl_cdecl_fn(llmod, ~"llvm.exp2.f32", + T_fn(~[T_f32()], T_f32())); + let exp2f64 = decl_cdecl_fn(llmod, ~"llvm.exp2.f64", + T_fn(~[T_f64()], T_f64())); + let logf32 = decl_cdecl_fn(llmod, ~"llvm.log.f32", + T_fn(~[T_f32()], T_f32())); + let logf64 = decl_cdecl_fn(llmod, ~"llvm.log.f64", + T_fn(~[T_f64()], T_f64())); + let log10f32 = decl_cdecl_fn(llmod, ~"llvm.log10.f32", + T_fn(~[T_f32()], T_f32())); + let log10f64 = decl_cdecl_fn(llmod, ~"llvm.log10.f64", + T_fn(~[T_f64()], T_f64())); + let log2f32 = decl_cdecl_fn(llmod, ~"llvm.log2.f32", + T_fn(~[T_f32()], T_f32())); + let log2f64 = decl_cdecl_fn(llmod, ~"llvm.log2.f64", + T_fn(~[T_f64()], T_f64())); + let fmaf32 = decl_cdecl_fn(llmod, ~"llvm.fma.f32", + T_fn(~[T_f32(), T_f32(), T_f32()], T_f32())); + let fmaf64 = decl_cdecl_fn(llmod, ~"llvm.fma.f64", + T_fn(~[T_f64(), T_f64(), T_f64()], T_f64())); + let fabsf32 = decl_cdecl_fn(llmod, ~"llvm.fabs.f32", + T_fn(~[T_f32()], T_f32())); + let fabsf64 = decl_cdecl_fn(llmod, ~"llvm.fabs.f64", + T_fn(~[T_f64()], T_f64())); + let floorf32 = decl_cdecl_fn(llmod, ~"llvm.floor.f32", + T_fn(~[T_f32()], T_f32())); + let floorf64 = decl_cdecl_fn(llmod, ~"llvm.floor.f64", + T_fn(~[T_f64()], T_f64())); + let ceilf32 = decl_cdecl_fn(llmod, ~"llvm.ceil.f32", + T_fn(~[T_f32()], T_f32())); + let ceilf64 = decl_cdecl_fn(llmod, ~"llvm.ceil.f64", + T_fn(~[T_f64()], T_f64())); + let truncf32 = decl_cdecl_fn(llmod, ~"llvm.trunc.f32", + T_fn(~[T_f32()], T_f32())); + let truncf64 = decl_cdecl_fn(llmod, ~"llvm.trunc.f64", + T_fn(~[T_f64()], T_f64())); + let intrinsics = HashMap(); intrinsics.insert(~"llvm.gcroot", gcroot); intrinsics.insert(~"llvm.gcread", gcread); @@ -2378,6 +2439,37 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { intrinsics.insert(~"llvm.memset.p0i8.i64", memset64); intrinsics.insert(~"llvm.trap", trap); intrinsics.insert(~"llvm.frameaddress", frameaddress); + intrinsics.insert(~"llvm.sqrt.f32", sqrtf32); + intrinsics.insert(~"llvm.sqrt.f64", sqrtf64); + intrinsics.insert(~"llvm.powi.f32", powif32); + intrinsics.insert(~"llvm.powi.f64", powif64); + intrinsics.insert(~"llvm.sin.f32", sinf32); + intrinsics.insert(~"llvm.sin.f64", sinf64); + intrinsics.insert(~"llvm.cos.f32", cosf32); + intrinsics.insert(~"llvm.cos.f64", cosf64); + intrinsics.insert(~"llvm.pow.f32", powf32); + intrinsics.insert(~"llvm.pow.f64", powf64); + intrinsics.insert(~"llvm.exp.f32", expf32); + intrinsics.insert(~"llvm.exp.f64", expf64); + intrinsics.insert(~"llvm.exp2.f32", exp2f32); + intrinsics.insert(~"llvm.exp2.f64", exp2f64); + intrinsics.insert(~"llvm.log.f32", logf32); + intrinsics.insert(~"llvm.log.f64", logf64); + intrinsics.insert(~"llvm.log10.f32", log10f32); + intrinsics.insert(~"llvm.log10.f64", log10f64); + intrinsics.insert(~"llvm.log2.f32", log2f32); + intrinsics.insert(~"llvm.log2.f64", log2f64); + intrinsics.insert(~"llvm.fma.f32", fmaf32); + intrinsics.insert(~"llvm.fma.f64", fmaf64); + intrinsics.insert(~"llvm.fabs.f32", fabsf32); + intrinsics.insert(~"llvm.fabs.f64", fabsf64); + intrinsics.insert(~"llvm.floor.f32", floorf32); + intrinsics.insert(~"llvm.floor.f64", floorf64); + intrinsics.insert(~"llvm.ceil.f32", ceilf32); + intrinsics.insert(~"llvm.ceil.f64", ceilf64); + intrinsics.insert(~"llvm.trunc.f32", truncf32); + intrinsics.insert(~"llvm.trunc.f64", truncf64); + return intrinsics; } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 4fe7c307d5977..8563a79e3d20c 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -973,7 +973,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item, let llcast = PointerCast(bcx, llcast, T_ptr(T_i8())); call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty)); } - } + } ~"addr_of" => { Store(bcx, get_param(decl, first_real_arg), fcx.llretptr); } @@ -1024,6 +1024,164 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item, T_ptr(T_nil())); Store(bcx, morestack_addr, fcx.llretptr); } + ~"sqrtf32" => { + let x = get_param(decl, first_real_arg); + let sqrtf = ccx.intrinsics.get(~"llvm.sqrt.f32"); + Store(bcx, Call(bcx, sqrtf, ~[x]), fcx.llretptr); + } + ~"sqrtf64" => { + let x = get_param(decl, first_real_arg); + let sqrtf = ccx.intrinsics.get(~"llvm.sqrt.f64"); + Store(bcx, Call(bcx, sqrtf, ~[x]), fcx.llretptr); + } + ~"powif32" => { + let a = get_param(decl, first_real_arg); + let x = get_param(decl, first_real_arg + 1u); + let powif = ccx.intrinsics.get(~"llvm.powi.f32"); + Store(bcx, Call(bcx, powif, ~[a, x]), fcx.llretptr); + } + ~"powif64" => { + let a = get_param(decl, first_real_arg); + let x = get_param(decl, first_real_arg + 1u); + let powif = ccx.intrinsics.get(~"llvm.powi.f64"); + Store(bcx, Call(bcx, powif, ~[a, x]), fcx.llretptr); + } + ~"sinf32" => { + let x = get_param(decl, first_real_arg); + let sinf = ccx.intrinsics.get(~"llvm.sin.f32"); + Store(bcx, Call(bcx, sinf, ~[x]), fcx.llretptr); + } + ~"sinf64" => { + let x = get_param(decl, first_real_arg); + let sinf = ccx.intrinsics.get(~"llvm.sin.f64"); + Store(bcx, Call(bcx, sinf, ~[x]), fcx.llretptr); + } + ~"cosf32" => { + let x = get_param(decl, first_real_arg); + let cosf = ccx.intrinsics.get(~"llvm.cos.f32"); + Store(bcx, Call(bcx, cosf, ~[x]), fcx.llretptr); + } + ~"cosf64" => { + let x = get_param(decl, first_real_arg); + let cosf = ccx.intrinsics.get(~"llvm.cos.f64"); + Store(bcx, Call(bcx, cosf, ~[x]), fcx.llretptr); + } + ~"powf32" => { + let a = get_param(decl, first_real_arg); + let x = get_param(decl, first_real_arg + 1u); + let powf = ccx.intrinsics.get(~"llvm.pow.f32"); + Store(bcx, Call(bcx, powf, ~[a, x]), fcx.llretptr); + } + ~"powf64" => { + let a = get_param(decl, first_real_arg); + let x = get_param(decl, first_real_arg + 1u); + let powf = ccx.intrinsics.get(~"llvm.pow.f64"); + Store(bcx, Call(bcx, powf, ~[a, x]), fcx.llretptr); + } + ~"expf32" => { + let x = get_param(decl, first_real_arg); + let expf = ccx.intrinsics.get(~"llvm.exp.f32"); + Store(bcx, Call(bcx, expf, ~[x]), fcx.llretptr); + } + ~"expf64" => { + let x = get_param(decl, first_real_arg); + let expf = ccx.intrinsics.get(~"llvm.exp.f64"); + Store(bcx, Call(bcx, expf, ~[x]), fcx.llretptr); + } + ~"exp2f32" => { + let x = get_param(decl, first_real_arg); + let exp2f = ccx.intrinsics.get(~"llvm.exp2.f32"); + Store(bcx, Call(bcx, exp2f, ~[x]), fcx.llretptr); + } + ~"exp2f64" => { + let x = get_param(decl, first_real_arg); + let exp2f = ccx.intrinsics.get(~"llvm.exp2.f64"); + Store(bcx, Call(bcx, exp2f, ~[x]), fcx.llretptr); + } + ~"logf32" => { + let x = get_param(decl, first_real_arg); + let logf = ccx.intrinsics.get(~"llvm.log.f32"); + Store(bcx, Call(bcx, logf, ~[x]), fcx.llretptr); + } + ~"logf64" => { + let x = get_param(decl, first_real_arg); + let logf = ccx.intrinsics.get(~"llvm.log.f64"); + Store(bcx, Call(bcx, logf, ~[x]), fcx.llretptr); + } + ~"log10f32" => { + let x = get_param(decl, first_real_arg); + let log10f = ccx.intrinsics.get(~"llvm.log10.f32"); + Store(bcx, Call(bcx, log10f, ~[x]), fcx.llretptr); + } + ~"log10f64" => { + let x = get_param(decl, first_real_arg); + let log10f = ccx.intrinsics.get(~"llvm.log10.f64"); + Store(bcx, Call(bcx, log10f, ~[x]), fcx.llretptr); + } + ~"log2f32" => { + let x = get_param(decl, first_real_arg); + let log2f = ccx.intrinsics.get(~"llvm.log2.f32"); + Store(bcx, Call(bcx, log2f, ~[x]), fcx.llretptr); + } + ~"log2f64" => { + let x = get_param(decl, first_real_arg); + let log2f = ccx.intrinsics.get(~"llvm.log2.f64"); + Store(bcx, Call(bcx, log2f, ~[x]), fcx.llretptr); + } + ~"fmaf32" => { + let a = get_param(decl, first_real_arg); + let b = get_param(decl, first_real_arg + 1u); + let c = get_param(decl, first_real_arg + 2u); + let fmaf = ccx.intrinsics.get(~"llvm.fma.f32"); + Store(bcx, Call(bcx, fmaf, ~[a, b, c]), fcx.llretptr); + } + ~"fmaf64" => { + let a = get_param(decl, first_real_arg); + let b = get_param(decl, first_real_arg + 1u); + let c = get_param(decl, first_real_arg + 2u); + let fmaf = ccx.intrinsics.get(~"llvm.fma.f64"); + Store(bcx, Call(bcx, fmaf, ~[a, b, c]), fcx.llretptr); + } + ~"fabsf32" => { + let x = get_param(decl, first_real_arg); + let fabsf = ccx.intrinsics.get(~"llvm.fabs.f32"); + Store(bcx, Call(bcx, fabsf, ~[x]), fcx.llretptr); + } + ~"fabsf64" => { + let x = get_param(decl, first_real_arg); + let fabsf = ccx.intrinsics.get(~"llvm.fabs.f64"); + Store(bcx, Call(bcx, fabsf, ~[x]), fcx.llretptr); + } + ~"floorf32" => { + let x = get_param(decl, first_real_arg); + let floorf = ccx.intrinsics.get(~"llvm.floor.f32"); + Store(bcx, Call(bcx, floorf, ~[x]), fcx.llretptr); + } + ~"floorf64" => { + let x = get_param(decl, first_real_arg); + let floorf = ccx.intrinsics.get(~"llvm.floor.f64"); + Store(bcx, Call(bcx, floorf, ~[x]), fcx.llretptr); + } + ~"ceilf32" => { + let x = get_param(decl, first_real_arg); + let ceilf = ccx.intrinsics.get(~"llvm.ceil.f32"); + Store(bcx, Call(bcx, ceilf, ~[x]), fcx.llretptr); + } + ~"ceilf64" => { + let x = get_param(decl, first_real_arg); + let ceilf = ccx.intrinsics.get(~"llvm.ceil.f64"); + Store(bcx, Call(bcx, ceilf, ~[x]), fcx.llretptr); + } + ~"truncf32" => { + let x = get_param(decl, first_real_arg); + let truncf = ccx.intrinsics.get(~"llvm.trunc.f32"); + Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr); + } + ~"truncf64" => { + let x = get_param(decl, first_real_arg); + let truncf = ccx.intrinsics.get(~"llvm.trunc.f64"); + Store(bcx, Call(bcx, truncf, ~[x]), fcx.llretptr); + } _ => { // Could we make this an enum rather than a string? does it get // checked earlier? diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 53889369361fd..0eabd36996726 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -108,6 +108,15 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint) ~"visit_tydesc" | ~"forget" | ~"addr_of" | ~"frame_address" | ~"morestack_addr" => 0, + ~"sqrtf32" | ~"sqrtf64" | ~"powif32" | ~"powif64" | + ~"sinf32" | ~"sinf64" | ~"cosf32" | ~"cosf64" | + ~"powf32" | ~"powf64" | ~"expf32" | ~"expf64" | + ~"exp2f32" | ~"exp2f64" | ~"logf32" | ~"logf64" | + ~"log10f32"| ~"log10f64"| ~"log2f32" | ~"log2f64" | + ~"fmaf32" | ~"fmaf64" | ~"fabsf32" | ~"fabsf64" | + ~"floorf32"| ~"floorf64"| ~"ceilf32" | ~"ceilf64" | + ~"truncf32"| ~"truncf64" => 0, + // would be cool to make these an enum instead of strings! _ => fail ~"unknown intrinsic in type_use" }; diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index b24550f2bc647..079e624c20f3f 100644 --- a/src/librustc/middle/typeck/check.rs +++ b/src/librustc/middle/typeck/check.rs @@ -2872,6 +2872,136 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { ~"morestack_addr" => { (0u, ~[], ty::mk_nil_ptr(tcx)) } + + ~"sqrtf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"sqrtf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"powif32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx)), + arg(ast::by_copy, ty::mk_i32(tcx))], + ty::mk_f32(tcx)) + } + ~"powif64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx)), + arg(ast::by_copy, ty::mk_i32(tcx))], + ty::mk_f64(tcx)) + } + ~"sinf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"sinf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"cosf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"cosf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"powf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx)), + arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"powf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx)), + arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"expf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"expf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"exp2f32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"exp2f64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"logf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"logf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"log10f32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"log10f64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"log2f32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"log2f64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"fmaf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx)), + arg(ast::by_copy, ty::mk_f32(tcx)), + arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"fmaf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx)), + arg(ast::by_copy, ty::mk_f64(tcx)), + arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"fabsf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"fabsf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"floorf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"floorf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"ceilf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"ceilf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + ~"truncf32" => { + (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], + ty::mk_f32(tcx)) + } + ~"truncf64" => { + (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))], + ty::mk_f64(tcx)) + } + other => { tcx.sess.span_err(it.span, ~"unrecognized intrinsic function: `" + other + ~"`"); diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs new file mode 100644 index 0000000000000..3512ccf5fcf99 --- /dev/null +++ b/src/test/run-pass/intrinsics-math.rs @@ -0,0 +1,88 @@ +#[abi = "rust-intrinsic"] +extern mod rusti { + fn sqrtf32(x: f32) -> f32; + fn sqrtf64(x: f64) -> f64; + fn powif32(a: f32, x: i32) -> f32; + fn powif64(a: f64, x: i32) -> f64; + fn sinf32(x: f32) -> f32; + fn sinf64(x: f64) -> f64; + fn cosf32(x: f32) -> f32; + fn cosf64(x: f64) -> f64; + fn powf32(a: f32, x: f32) -> f32; + fn powf64(a: f64, x: f64) -> f64; + fn expf32(x: f32) -> f32; + fn expf64(x: f64) -> f64; + fn exp2f32(x: f32) -> f32; + fn exp2f64(x: f64) -> f64; + fn logf32(x: f32) -> f32; + fn logf64(x: f64) -> f64; + fn log10f32(x: f32) -> f32; + fn log10f64(x: f64) -> f64; + fn log2f32(x: f32) -> f32; + fn log2f64(x: f64) -> f64; + fn fmaf32(a: f32, b: f32, c: f32) -> f32; + fn fmaf64(a: f64, b: f64, c: f64) -> f64; + fn fabsf32(x: f32) -> f32; + fn fabsf64(x: f64) -> f64; + fn floorf32(x: f32) -> f32; + fn floorf64(x: f64) -> f64; + fn ceilf32(x: f32) -> f32; + fn ceilf64(x: f64) -> f64; + fn truncf32(x: f32) -> f32; + fn truncf64(x: f64) -> f64; +} + +fn main() { + + use rusti::*; + + assert(sqrtf32(64f32) == 8f32); + assert(sqrtf64(64f64) == 8f64); + + assert(powif32(25f32, -2i32) == 0.0016f32); + assert(powif64(23.2f64, 2i32) == 538.24f64); + + assert(sinf32(0f32) == 0f32); + assert(sinf64(f64::consts::pi / 2f64) == 1f64); + + assert(cosf32(0f32) == 1f32); + assert(cosf64(f64::consts::pi * 2f64) == 1f64); + + assert(powf32(25f32, -2f32) == 0.0016f32); + assert(powf64(400f64, 0.5f64) == 20f64); + + assert(expf32(1f32) == f32::consts::e); + assert(expf64(1f64) == f64::consts::e); + + assert(exp2f32(10f32) == 1024f32); + assert(exp2f64(50f64) == 1125899906842624f64); + + assert(logf32(f32::consts::e) == 1f32); + assert(logf64(1f64) == 0f64); + + assert(log10f32(10f32) == 1f32); + assert(log10f64(f64::consts::e) == f64::consts::log10_e); + + assert(log2f32(8f32) == 3f32); + assert(log2f64(f64::consts::e) == f64::consts::log2_e); + + assert(fmaf32(1.0f32, 2.0f32, 5.0f32) == 7.0f32); + assert(fmaf64(0.0f64, -2.0f64, f64::consts::e) == f64::consts::e); + + assert(fabsf32(-1.0f32) == 1.0f32); + assert(fabsf64(34.2f64) == 34.2f64); + + assert(floorf32(3.8f32) == 3.0f32); + assert(floorf64(-1.1f64) == -2.0f64); + + // Causes linker error + // undefined reference to llvm.ceil.f32/64 + //assert(ceilf32(-2.3f32) == -2.0f32); + //assert(ceilf64(3.8f64) == 4.0f64); + + // Causes linker error + // undefined reference to llvm.trunc.f32/64 + //assert(truncf32(0.1f32) == 0.0f32); + //assert(truncf64(-0.1f64) == 0.0f64); + +}