forked from M-Labs/nac3
core: reduce code duplication in codegen/extern_fns (#453)
Used macros to reduce code duplication in `codegen/extern_fns` Reviewed-on: M-Labs/nac3#453 Co-authored-by: abdul124 <ar@m-labs.hk> Co-committed-by: abdul124 <ar@m-labs.hk>
This commit is contained in:
parent
88b72af2d1
commit
eeb474f9e6
|
@ -4,514 +4,97 @@ 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";
|
||||
/// Macro to generate extern function
|
||||
/// Both function return type and function parameter type are `FloatValue`
|
||||
///
|
||||
/// Arguments:
|
||||
/// * `unary/binary`: Whether the extern function requires one (unary) or two (binary) operands
|
||||
/// * `$fn_name:ident`: The identifier of the rust function to be generated
|
||||
/// * `$extern_fn:literal`: Name of underlying extern function
|
||||
///
|
||||
/// Optional Arguments:
|
||||
/// * `$(,$attributes:literal)*)`: Attributes linked with the extern function
|
||||
/// The default attributes are "mustprogress", "nofree", "nounwind", "willreturn", and "writeonly"
|
||||
/// These will be used unless other attributes are specified
|
||||
/// * `$(,$args:ident)*`: Operands of the extern function
|
||||
/// The data type of these operands will be set to `FloatValue`
|
||||
///
|
||||
macro_rules! generate_extern_fn {
|
||||
("unary", $fn_name:ident, $extern_fn:literal) => {
|
||||
generate_extern_fn!($fn_name, $extern_fn, arg, "mustprogress", "nofree", "nounwind", "willreturn", "writeonly");
|
||||
};
|
||||
("unary", $fn_name:ident, $extern_fn:literal $(,$attributes:literal)*) => {
|
||||
generate_extern_fn!($fn_name, $extern_fn, arg $(,$attributes)*);
|
||||
};
|
||||
("binary", $fn_name:ident, $extern_fn:literal) => {
|
||||
generate_extern_fn!($fn_name, $extern_fn, arg1, arg2, "mustprogress", "nofree", "nounwind", "willreturn", "writeonly");
|
||||
};
|
||||
("binary", $fn_name:ident, $extern_fn:literal $(,$attributes:literal)*) => {
|
||||
generate_extern_fn!($fn_name, $extern_fn, arg1, arg2 $(,$attributes)*);
|
||||
};
|
||||
($fn_name:ident, $extern_fn:literal $(,$args:ident)* $(,$attributes:literal)*) => {
|
||||
#[doc = concat!("Invokes the [`", stringify!($extern_fn), "`](https://en.cppreference.com/w/c/numeric/math/", stringify!($llvm_name), ") function." )]
|
||||
pub fn $fn_name<'ctx>(
|
||||
ctx: &CodeGenContext<'ctx, '_>
|
||||
$(,$args: FloatValue<'ctx>)*,
|
||||
name: Option<&str>,
|
||||
) -> FloatValue<'ctx> {
|
||||
const FN_NAME: &str = $extern_fn;
|
||||
|
||||
let llvm_f64 = ctx.ctx.f64_type();
|
||||
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||
let llvm_f64 = ctx.ctx.f64_type();
|
||||
$(debug_assert_eq!($args.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),
|
||||
);
|
||||
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||
let fn_type = llvm_f64.fn_type(&[$($args.get_type().into()),*], false);
|
||||
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||
for attr in [$($attributes),*] {
|
||||
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, &[$($args.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()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
generate_extern_fn!("unary", call_tan, "tan");
|
||||
generate_extern_fn!("unary", call_asin, "asin");
|
||||
generate_extern_fn!("unary", call_acos, "acos");
|
||||
generate_extern_fn!("unary", call_atan, "atan");
|
||||
generate_extern_fn!("unary", call_sinh, "sinh");
|
||||
generate_extern_fn!("unary", call_cosh, "cosh");
|
||||
generate_extern_fn!("unary", call_tanh, "tanh");
|
||||
generate_extern_fn!("unary", call_asinh, "asinh");
|
||||
generate_extern_fn!("unary", call_acosh, "acosh");
|
||||
generate_extern_fn!("unary", call_atanh, "atanh");
|
||||
generate_extern_fn!("unary", call_expm1, "expm1");
|
||||
generate_extern_fn!(
|
||||
"unary",
|
||||
call_cbrt,
|
||||
"cbrt",
|
||||
"mustprogress",
|
||||
"nofree",
|
||||
"nosync",
|
||||
"nounwind",
|
||||
"readonly",
|
||||
"willreturn"
|
||||
);
|
||||
generate_extern_fn!("unary", call_erf, "erf", "nounwind");
|
||||
generate_extern_fn!("unary", call_erfc, "erfc", "nounwind");
|
||||
generate_extern_fn!("unary", call_j1, "j1", "nounwind");
|
||||
|
||||
generate_extern_fn!("binary", call_atan2, "atan2");
|
||||
generate_extern_fn!("binary", call_hypot, "hypot", "nounwind");
|
||||
generate_extern_fn!("binary", call_nextafter, "nextafter", "nounwind");
|
||||
|
||||
/// Invokes the [`ldexp`](https://en.cppreference.com/w/c/numeric/math/ldexp) function.
|
||||
pub fn call_ldexp<'ctx>(
|
||||
|
@ -547,67 +130,3 @@ pub fn call_ldexp<'ctx>(
|
|||
.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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue