mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
translate-c: translate 80/128-bit long double literals
This commit is contained in:
parent
40bd93e2a2
commit
8bf4b3c611
@ -506,6 +506,9 @@ pub const FloatingLiteral = opaque {
|
||||
pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble;
|
||||
extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64;
|
||||
|
||||
pub const getValueAsApproximateQuadBits = ZigClangFloatingLiteral_getValueAsApproximateQuadBits;
|
||||
extern fn ZigClangFloatingLiteral_getValueAsApproximateQuadBits(*const FloatingLiteral, low: *u64, high: *u64) void;
|
||||
|
||||
pub const getBeginLoc = ZigClangFloatingLiteral_getBeginLoc;
|
||||
extern fn ZigClangFloatingLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation;
|
||||
|
||||
|
||||
@ -3936,11 +3936,26 @@ fn transCPtrCast(
|
||||
}
|
||||
|
||||
fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
|
||||
// TODO use something more accurate than widening to a larger float type and printing that result
|
||||
switch (expr.getRawSemantics()) {
|
||||
.IEEEhalf, // f16
|
||||
.IEEEsingle, // f32
|
||||
.IEEEdouble, // f64
|
||||
=> {},
|
||||
=> {
|
||||
var dbl = expr.getValueAsApproximateDouble();
|
||||
const is_negative = dbl < 0; // -0.0 is considered non-negative
|
||||
if (is_negative) dbl = -dbl;
|
||||
const str = if (dbl == @floor(dbl))
|
||||
try std.fmt.allocPrint(c.arena, "{d}.0", .{dbl})
|
||||
else
|
||||
try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
|
||||
var node = try Tag.float_literal.create(c.arena, str);
|
||||
if (is_negative) node = try Tag.negate.create(c.arena, node);
|
||||
return maybeSuppressResult(c, used, node);
|
||||
},
|
||||
.x87DoubleExtended, // f80
|
||||
.IEEEquad, // f128
|
||||
=> return transFloatingLiteralQuad(c, expr, used),
|
||||
else => |format| return fail(
|
||||
c,
|
||||
error.UnsupportedTranslation,
|
||||
@ -3949,14 +3964,44 @@ fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: R
|
||||
.{format},
|
||||
),
|
||||
}
|
||||
// TODO use something more accurate
|
||||
var dbl = expr.getValueAsApproximateDouble();
|
||||
const is_negative = dbl < 0;
|
||||
if (is_negative) dbl = -dbl;
|
||||
const str = if (dbl == @floor(dbl))
|
||||
try std.fmt.allocPrint(c.arena, "{d}.0", .{dbl})
|
||||
else
|
||||
try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
|
||||
}
|
||||
|
||||
fn transFloatingLiteralQuad(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
|
||||
assert(switch (expr.getRawSemantics()) {
|
||||
.x87DoubleExtended, .IEEEquad => true,
|
||||
else => false,
|
||||
});
|
||||
|
||||
var low: u64 = undefined;
|
||||
var high: u64 = undefined;
|
||||
expr.getValueAsApproximateQuadBits(&low, &high);
|
||||
var quad: f128 = @bitCast(low | @as(u128, high) << 64);
|
||||
const is_negative = quad < 0; // -0.0 is considered non-negative
|
||||
if (is_negative) quad = -quad;
|
||||
|
||||
// TODO implement decimal format for f128 <https://github.com/ziglang/zig/issues/1181>
|
||||
// in the meantime, if the value can be roundtripped by casting it to f64, serializing it to
|
||||
// the decimal format and parsing it back as the exact same f128 value, then use that serialized form
|
||||
const str = fmt_decimal: {
|
||||
var buf: [512]u8 = undefined; // should be large enough to print any f64 in decimal form
|
||||
const dbl: f64 = @floatCast(quad);
|
||||
const temp_str = if (dbl == @floor(dbl))
|
||||
std.fmt.bufPrint(&buf, "{d}.0", .{dbl}) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
}
|
||||
else
|
||||
std.fmt.bufPrint(&buf, "{d}", .{dbl}) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
const could_roundtrip = if (std.fmt.parseFloat(f128, temp_str)) |parsed_quad|
|
||||
quad == parsed_quad
|
||||
else |_|
|
||||
false;
|
||||
break :fmt_decimal if (could_roundtrip) try c.arena.dupe(u8, temp_str) else null;
|
||||
}
|
||||
// otherwise, fall back to the hexadecimal format
|
||||
orelse try std.fmt.allocPrint(c.arena, "{x}", .{quad});
|
||||
|
||||
var node = try Tag.float_literal.create(c.arena, str);
|
||||
if (is_negative) node = try Tag.negate.create(c.arena, node);
|
||||
return maybeSuppressResult(c, used, node);
|
||||
|
||||
@ -3245,6 +3245,17 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin
|
||||
return casted->getValueAsApproximateDouble();
|
||||
}
|
||||
|
||||
void ZigClangFloatingLiteral_getValueAsApproximateQuadBits(const ZigClangFloatingLiteral *self, uint64_t *low, uint64_t *high) {
|
||||
auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);
|
||||
llvm::APFloat apf = casted->getValue();
|
||||
bool ignored;
|
||||
apf.convert(llvm::APFloat::IEEEquad(), llvm::APFloat::rmNearestTiesToEven, &ignored);
|
||||
const llvm::APInt api = apf.bitcastToAPInt();
|
||||
const uint64_t *api_data = api.getRawData();
|
||||
*low = api_data[0];
|
||||
*high = api_data[1];
|
||||
}
|
||||
|
||||
struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *self) {
|
||||
auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);
|
||||
return bitcast(casted->getBeginLoc());
|
||||
|
||||
@ -1510,6 +1510,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st
|
||||
ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST,
|
||||
unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM);
|
||||
ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self);
|
||||
ZIG_EXTERN_C void ZigClangFloatingLiteral_getValueAsApproximateQuadBits(const ZigClangFloatingLiteral *self, uint64_t *low, uint64_t *high);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *);
|
||||
ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self);
|
||||
|
||||
|
||||
@ -1240,6 +1240,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\extern const float my_float = 1.0f;
|
||||
\\extern const double my_double = 1.0;
|
||||
\\extern const long double my_longdouble = 1.0l;
|
||||
\\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
|
||||
, &([_][]const u8{
|
||||
"pub const foo = @as(f32, 3.14);",
|
||||
"pub const bar = @as(c_longdouble, 16.0e-2);",
|
||||
@ -1250,13 +1251,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
"pub const foobar = -@as(c_longdouble, 73.0);",
|
||||
"pub export const my_float: f32 = 1.0;",
|
||||
"pub export const my_double: f64 = 1.0;",
|
||||
} ++ if (@bitSizeOf(c_longdouble) != 64) .{
|
||||
// TODO properly translate non-64-bit long doubles
|
||||
"source.h:10:42: warning: unsupported floating point constant format",
|
||||
"source.h:10:26: warning: unable to translate variable initializer, demoted to extern",
|
||||
"pub extern const my_longdouble: c_longdouble;",
|
||||
} else .{
|
||||
"pub export const my_longdouble: c_longdouble = 1.0;",
|
||||
switch (@bitSizeOf(c_longdouble)) {
|
||||
// TODO implement decimal format for f128 <https://github.com/ziglang/zig/issues/1181>
|
||||
// (so that f80/f128 values not exactly representable as f64 can be emitted in decimal form)
|
||||
80 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159ep0;",
|
||||
128 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159e05f1e2674d21p0;",
|
||||
else => "pub export const my_extended_precision_longdouble: c_longdouble = 1.0000000000000002;",
|
||||
},
|
||||
}));
|
||||
|
||||
cases.add("macro defines hexadecimal float",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user