forked from M-Labs/nac3
David Mak
51671800b6
We will need to reuse them when implementing elementwise function application for ndarrays.
613 lines
21 KiB
Rust
613 lines
21 KiB
Rust
use inkwell::attributes::{Attribute, AttributeLoc};
|
|
use inkwell::values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue};
|
|
use itertools::Either;
|
|
|
|
use crate::codegen::CodeGenContext;
|
|
|
|
/// Invokes the [`tan`](https://en.cppreference.com/w/c/numeric/math/tan) function.
|
|
pub fn call_tan<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "tan";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`asin`](https://en.cppreference.com/w/c/numeric/math/asin) function.
|
|
pub fn call_asin<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "asin";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`acos`](https://en.cppreference.com/w/c/numeric/math/acos) function.
|
|
pub fn call_acos<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "acos";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`atan`](https://en.cppreference.com/w/c/numeric/math/atan) function.
|
|
pub fn call_atan<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "atan";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`sinh`](https://en.cppreference.com/w/c/numeric/math/sinh) function.
|
|
pub fn call_sinh<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "sinh";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`cosh`](https://en.cppreference.com/w/c/numeric/math/cosh) function.
|
|
pub fn call_cosh<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "cosh";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`tanh`](https://en.cppreference.com/w/c/numeric/math/tanh) function.
|
|
pub fn call_tanh<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "tanh";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`asinh`](https://en.cppreference.com/w/c/numeric/math/asinh) function.
|
|
pub fn call_asinh<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "asinh";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`acosh`](https://en.cppreference.com/w/c/numeric/math/acosh) function.
|
|
pub fn call_acosh<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "acosh";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`atanh`](https://en.cppreference.com/w/c/numeric/math/atanh) function.
|
|
pub fn call_atanh<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "atanh";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`expm1`](https://en.cppreference.com/w/c/numeric/math/expm1) function.
|
|
pub fn call_expm1<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "expm1";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`cbrt`](https://en.cppreference.com/w/c/numeric/math/cbrt) function.
|
|
pub fn call_cbrt<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "cbrt";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nosync", "nounwind", "readonly", "willreturn"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`erf`](https://en.cppreference.com/w/c/numeric/math/erf) function.
|
|
pub fn call_erf<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "erf";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0)
|
|
);
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`erfc`](https://en.cppreference.com/w/c/numeric/math/erfc) function.
|
|
pub fn call_erfc<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "erfc";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0)
|
|
);
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`j1`](https://www.gnu.org/software/libc/manual/html_node/Special-Functions.html#index-j1)
|
|
/// function.
|
|
pub fn call_j1<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "j1";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0)
|
|
);
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`atan2`](https://en.cppreference.com/w/c/numeric/math/atan2) function.
|
|
pub fn call_atan2<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
y: FloatValue<'ctx>,
|
|
x: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "atan2";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(y.get_type(), llvm_f64);
|
|
debug_assert_eq!(x.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[y.into(), x.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`ldexp`](https://en.cppreference.com/w/c/numeric/math/ldexp) function.
|
|
pub fn call_ldexp<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
arg: FloatValue<'ctx>,
|
|
exp: IntValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "ldexp";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
let llvm_i32 = ctx.ctx.i32_type();
|
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
|
debug_assert_eq!(exp.get_type(), llvm_i32);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_i32.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn"] {
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
|
);
|
|
}
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[arg.into(), exp.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`hypot`](https://en.cppreference.com/w/c/numeric/math/hypot) function.
|
|
pub fn call_hypot<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
x: FloatValue<'ctx>,
|
|
y: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "hypot";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(x.get_type(), llvm_f64);
|
|
debug_assert_eq!(y.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0)
|
|
);
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[x.into(), y.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
}
|
|
|
|
/// Invokes the [`nextafter`](https://en.cppreference.com/w/c/numeric/math/nextafter) function.
|
|
pub fn call_nextafter<'ctx>(
|
|
ctx: &CodeGenContext<'ctx, '_>,
|
|
from: FloatValue<'ctx>,
|
|
to: FloatValue<'ctx>,
|
|
name: Option<&str>,
|
|
) -> FloatValue<'ctx> {
|
|
const FN_NAME: &str = "nextafter";
|
|
|
|
let llvm_f64 = ctx.ctx.f64_type();
|
|
debug_assert_eq!(from.get_type(), llvm_f64);
|
|
debug_assert_eq!(to.get_type(), llvm_f64);
|
|
|
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_f64.into()], false);
|
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
func.add_attribute(
|
|
AttributeLoc::Function,
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0)
|
|
);
|
|
|
|
func
|
|
});
|
|
|
|
ctx.builder
|
|
.build_call(extern_fn, &[from.into(), to.into()], name.unwrap_or_default())
|
|
.map(CallSiteValue::try_as_basic_value)
|
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
.map(Either::unwrap_left)
|
|
.unwrap()
|
|
} |