Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2676,7 +2676,10 @@ impl CTypeKind {

pub fn is_floating_type(&self) -> bool {
use CTypeKind::*;
matches!(self, Float | Double | LongDouble | Half | BFloat16)
matches!(
self,
Float | Double | LongDouble | Float128 | Half | BFloat16
)
}

pub fn as_underlying_decl(&self) -> Option<CDeclId> {
Expand Down Expand Up @@ -2731,6 +2734,7 @@ impl CTypeKind {
(ULongLong, ty) | (ty, ULongLong) if int(ty) => ULongLong,

(LongDouble, ty) | (ty, LongDouble) if float(ty) || int(ty) => LongDouble,
(Float128, ty) | (ty, Float128) if float(ty) || int(ty) => Float128,

(Int128, ty) | (ty, Int128) if int(ty) => Int128,
(UInt128, ty) | (ty, UInt128) if int(ty) => UInt128,
Expand Down
52 changes: 43 additions & 9 deletions c2rust-transpile/src/translator/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,29 @@ impl<'c> Translation<'c> {
"__builtin_huge_valf" => Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["core", "f32", "INFINITY"]),
)),
"__builtin_huge_val" | "__builtin_huge_vall" => Ok(WithStmts::new_val(
"__builtin_huge_val" => Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["core", "f64", "INFINITY"]),
)),
"__builtin_huge_vall" => {
self.use_crate(ExternCrate::F128);

Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["f128", "f128", "INFINITY"]),
))
}
"__builtin_inff" => Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["core", "f32", "INFINITY"]),
)),
"__builtin_inf" | "__builtin_infl" => Ok(WithStmts::new_val(
"__builtin_inf" => Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["core", "f64", "INFINITY"]),
)),
"__builtin_infl" => {
self.use_crate(ExternCrate::F128);

Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["f128", "f128", "INFINITY"]),
))
}
"__builtin_nanf" => Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["core", "f32", "NAN"]),
)),
Expand All @@ -98,15 +112,9 @@ impl<'c> Translation<'c> {
))
}
"__builtin_signbit" | "__builtin_signbitf" | "__builtin_signbitl" => {
// Long doubles require the Float trait from num_traits to call this method
if builtin_name == "__builtin_signbitl" {
self.with_cur_file_item_store(|item_store| {
item_store.add_use(true, vec!["num_traits".into()], "Float");
});
}
self.import_num_traits(args[0])?;

let val = self.convert_expr(ctx.used(), args[0], None)?;

Ok(val.map(|v| {
let val = mk().method_call_expr(v, "is_sign_negative", vec![]);

Expand Down Expand Up @@ -149,10 +157,14 @@ impl<'c> Translation<'c> {
Ok(val.map(|x| mk().method_call_expr(x, "swap_bytes", vec![])))
}
"__builtin_fabs" | "__builtin_fabsf" | "__builtin_fabsl" => {
self.import_num_traits(args[0])?;

let val = self.convert_expr(ctx.used(), args[0], None)?;
Ok(val.map(|x| mk().method_call_expr(x, "abs", vec![])))
}
"__builtin_isfinite" | "__builtin_isnan" => {
self.import_num_traits(args[0])?;

let val = self.convert_expr(ctx.used(), args[0], None)?;

let seg = match builtin_name {
Expand All @@ -166,6 +178,8 @@ impl<'c> Translation<'c> {
}))
}
"__builtin_isinf_sign" => {
self.import_num_traits(args[0])?;

// isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0
let val = self.convert_expr(ctx.used(), args[0], None)?;
Ok(val.map(|x| {
Expand Down Expand Up @@ -723,6 +737,26 @@ impl<'c> Translation<'c> {
}
}

fn import_num_traits(&self, arg_id: CExprId) -> TranslationResult<()> {
let arg_type_id = self.ast_context[arg_id]
.kind
.get_qual_type()
.ok_or_else(|| format_err!("bad arg type"))?;
let arg_type_kind = &self.ast_context.resolve_type(arg_type_id.ctype).kind;

match arg_type_kind {
CTypeKind::LongDouble | CTypeKind::Float128 => {
self.use_crate(ExternCrate::NumTraits);
self.with_cur_file_item_store(|item_store| {
item_store.add_use(true, vec!["num_traits".into()], "Float");
});
}
_ => {}
}

Ok(())
}

// This translation logic handles converting code that uses
// https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
fn convert_overflow_arith(
Expand Down
2 changes: 1 addition & 1 deletion c2rust-transpile/src/translator/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl<'c> Translation<'c> {
c_str.to_owned()
};
let val = match self.ast_context.resolve_type(ty.ctype).kind {
CTypeKind::LongDouble => {
CTypeKind::LongDouble | CTypeKind::Float128 => {
if ctx.is_const {
return Err(format_translation_err!(
None,
Expand Down
45 changes: 29 additions & 16 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1720,7 +1720,7 @@ impl<'c> Translation<'c> {

// The f128 crate doesn't currently provide a way to const initialize
// values, except for common mathematical constants
if let CTypeKind::LongDouble = self.ast_context[qtype.ctype].kind {
if let CTypeKind::LongDouble | CTypeKind::Float128 = self.ast_context[qtype.ctype].kind {
return true;
}

Expand Down Expand Up @@ -3067,7 +3067,7 @@ impl<'c> Translation<'c> {
// so type annotation is need for 0-init ints and floats at the moment, but
// they could be simplified in favor of type suffixes
Bool | Char | SChar | Short | Int | Long | LongLong | UChar | UShort | UInt | ULong
| ULongLong | LongDouble | Int128 | UInt128 => initializer.is_none(),
| ULongLong | LongDouble | Float128 | Int128 | UInt128 => initializer.is_none(),
Float | Double => initializer.is_none(),
Struct(_) | Union(_) | Enum(_) => false,
Function(..) => unreachable!("Can't have a function directly as a type"),
Expand Down Expand Up @@ -4479,20 +4479,30 @@ impl<'c> Translation<'c> {
| CastKind::BooleanToSignedIntegral => {
let target_ty = self.convert_type(target_cty.ctype)?;

if let CTypeKind::LongDouble = target_ty_kind {
if ctx.is_const {
return Err(format_translation_err!(
None,
"f128 cannot be used in constants because \
`f128::f128::new` is not `const`",
));
}
if let CTypeKind::LongDouble | CTypeKind::Float128 = target_ty_kind {
if let CTypeKind::LongDouble | CTypeKind::Float128 =
self.ast_context[source_cty.ctype].kind
{
// These are both converted to `f128`, so a cast between the two should
// just be a no-op.
Ok(val)
} else {
if ctx.is_const {
return Err(format_translation_err!(
None,
"f128 cannot be used in constants because \
`f128::f128::new` is not `const`",
));
}

self.use_crate(ExternCrate::F128);
self.use_crate(ExternCrate::F128);

let fn_path = mk().abs_path_expr(vec!["f128", "f128", "new"]);
Ok(val.map(|val| mk().call_expr(fn_path, vec![val])))
} else if let CTypeKind::LongDouble = self.ast_context[source_cty.ctype].kind {
let fn_path = mk().abs_path_expr(vec!["f128", "f128", "new"]);
Ok(val.map(|val| mk().call_expr(fn_path, vec![val])))
}
} else if let CTypeKind::LongDouble | CTypeKind::Float128 =
self.ast_context[source_cty.ctype].kind
{
self.f128_cast_to(val, target_ty_kind)
} else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind {
// Casts targeting `enum` types...
Expand Down Expand Up @@ -4631,7 +4641,7 @@ impl<'c> Translation<'c> {
))
} else if resolved_ty.is_floating_type() {
match self.ast_context[ty_id].kind {
CTypeKind::LongDouble => {
CTypeKind::LongDouble | CTypeKind::Float128 => {
self.use_crate(ExternCrate::F128);
Ok(WithStmts::new_val(
mk().abs_path_expr(vec!["f128", "f128", "ZERO"]),
Expand Down Expand Up @@ -4874,7 +4884,10 @@ impl<'c> Translation<'c> {
};

// The backup is to just compare against zero
let zero = if ty.is_floating_type() {
let zero = if let CTypeKind::LongDouble | CTypeKind::Float128 = ty {
self.use_crate(ExternCrate::F128);
mk().abs_path_expr(vec!["f128", "f128", "ZERO"])
} else if ty.is_floating_type() {
mk().lit_expr(mk().float_unsuffixed_lit("0."))
} else {
mk().lit_expr(mk().int_unsuffixed_lit(0))
Expand Down
24 changes: 13 additions & 11 deletions c2rust-transpile/src/translator/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,16 +224,17 @@ impl<'c> Translation<'c> {
let lhs_type = self.convert_type(compute_lhs_type_id.ctype)?;

// We can't simply as-cast into a non primitive like f128
let lhs = if compute_lhs_resolved_ty.kind == CTypeKind::LongDouble {
self.use_crate(ExternCrate::F128);
let lhs =
if let CTypeKind::LongDouble | CTypeKind::Float128 = compute_lhs_resolved_ty.kind {
self.use_crate(ExternCrate::F128);

let fn_path = mk().abs_path_expr(vec!["f128", "f128", "from"]);
let args = vec![read];
let fn_path = mk().abs_path_expr(vec!["f128", "f128", "from"]);
let args = vec![read];

mk().call_expr(fn_path, args)
} else {
mk().cast_expr(read, lhs_type)
};
mk().call_expr(fn_path, args)
} else {
mk().cast_expr(read, lhs_type)
};
let ty = self.convert_type(compute_res_type_id.ctype)?;
let mut val = self.convert_binary_operator(
ctx,
Expand All @@ -253,7 +254,8 @@ impl<'c> Translation<'c> {
val.result_map(|val| {
self.convert_cast_to_enum(ctx, lhs_type_id.ctype, enum_id, None, val)
})?
} else if compute_lhs_resolved_ty.kind == CTypeKind::LongDouble {
} else if let CTypeKind::LongDouble | CTypeKind::Float128 = compute_lhs_resolved_ty.kind
{
// We can't as-cast from a non primitive like f128 back to the result_type
self.f128_cast_to(val, resolve_lhs_kind)?
} else {
Expand Down Expand Up @@ -739,7 +741,7 @@ impl<'c> Translation<'c> {
// TODO: If rust gets f16 support:
// CTypeKind::Half |
CTypeKind::Float | CTypeKind::Double => mk().lit_expr(mk().float_unsuffixed_lit("1.")),
CTypeKind::LongDouble => {
CTypeKind::LongDouble | CTypeKind::Float128 => {
self.use_crate(ExternCrate::F128);

let fn_path = mk().abs_path_expr(vec!["f128", "f128", "new"]);
Expand Down Expand Up @@ -802,7 +804,7 @@ impl<'c> Translation<'c> {
CTypeKind::Float | CTypeKind::Double => {
mk().lit_expr(mk().float_unsuffixed_lit("1."))
}
CTypeKind::LongDouble => {
CTypeKind::LongDouble | CTypeKind::Float128 => {
self.use_crate(ExternCrate::F128);

let fn_path = mk().abs_path_expr(vec!["f128", "f128", "new"]);
Expand Down
37 changes: 37 additions & 0 deletions c2rust-transpile/tests/snapshots/f128.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <stdbool.h>
#include <math.h>

void long_double_test(void) {
long double one = 1.0l;
long double zero;
long double add = one + zero;
long double huge = __builtin_huge_vall();

int i = 1;
float f = 1.0f;
long double cast_from_int = i;
long double cast_from_float = f;

bool is_inf = isinf(huge);
if (one) {
int dummy;
}
}

void float128_test(void) {
__float128 one = 1.0q;
__float128 zero;
__float128 add = one + zero;
__float128 huge = __builtin_huge_vall();

int i = 1;
float f = 1.0f;
__float128 cast_from_int = i;
__float128 cast_from_float = f;
long double ld_from_float128 = one;

bool is_inf = isinf(huge);
if (one) {
int dummy;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
source: c2rust-transpile/tests/snapshots.rs
expression: cat tests/snapshots/f128.2021.rs
---
#![allow(
dead_code,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_assignments,
unused_mut
)]
#![deny(unsafe_op_in_unsafe_fn)]
use ::num_traits::Float;
#[no_mangle]
pub unsafe extern "C" fn long_double_test() {
unsafe {
let mut one: ::f128::f128 = ::f128::f128::new(1.0);
let mut zero: ::f128::f128 = ::f128::f128::ZERO;
let mut add: ::f128::f128 = one + zero;
let mut huge: ::f128::f128 = ::f128::f128::INFINITY;
let mut i: ::core::ffi::c_int = 1 as ::core::ffi::c_int;
let mut f: ::core::ffi::c_float = 1.0f32;
let mut cast_from_int: ::f128::f128 = ::f128::f128::new(i);
let mut cast_from_float: ::f128::f128 = ::f128::f128::new(f);
let mut is_inf: bool = if huge.is_infinite() {
if huge.is_sign_positive() { 1 } else { -1 }
} else {
0
} != 0;
if one != ::f128::f128::ZERO {
let mut dummy: ::core::ffi::c_int = 0;
}
}
}
#[no_mangle]
pub unsafe extern "C" fn float128_test() {
unsafe {
let mut one: ::f128::f128 = ::f128::f128::new(1.0);
let mut zero: ::f128::f128 = ::f128::f128::ZERO;
let mut add: ::f128::f128 = one + zero;
let mut huge: ::f128::f128 = ::f128::f128::INFINITY;
let mut i: ::core::ffi::c_int = 1 as ::core::ffi::c_int;
let mut f: ::core::ffi::c_float = 1.0f32;
let mut cast_from_int: ::f128::f128 = ::f128::f128::new(i);
let mut cast_from_float: ::f128::f128 = ::f128::f128::new(f);
let mut ld_from_float128: ::f128::f128 = one;
let mut is_inf: bool = if huge.is_infinite() {
if huge.is_sign_positive() { 1 } else { -1 }
} else {
0
} != 0;
if one != ::f128::f128::ZERO {
let mut dummy: ::core::ffi::c_int = 0;
}
}
}
Loading
Loading