authorgravatar for carl@astholm.seCarl Åstholm <carl@astholm.se> 2023-11-01 19:12:54+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-11-21 14:14:01+02:00
log8bf4b3c611b39fc39bad2a6c657541fa13973dea
tree663c8227fe167c7ad189162d7337e49bf22a747f
parent40bd93e2a24e3bdebd4f6454cfcffc51e5aaeeae

translate-c: translate 80/128-bit long double literals


5 files changed, 77 insertions(+), 15 deletions(-)

src/clang.zig+3
...@@ -506,6 +506,9 @@ pub const FloatingLiteral = opaque {...@@ -506,6 +506,9 @@ pub const FloatingLiteral = opaque {
506 pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble;506 pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble;
507 extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64;507 extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64;
508508
509 pub const getValueAsApproximateQuadBits = ZigClangFloatingLiteral_getValueAsApproximateQuadBits;
510 extern fn ZigClangFloatingLiteral_getValueAsApproximateQuadBits(*const FloatingLiteral, low: *u64, high: *u64) void;
511
509 pub const getBeginLoc = ZigClangFloatingLiteral_getBeginLoc;512 pub const getBeginLoc = ZigClangFloatingLiteral_getBeginLoc;
510 extern fn ZigClangFloatingLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation;513 extern fn ZigClangFloatingLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation;
511514
src/translate_c.zig+54-9
...@@ -3936,11 +3936,26 @@ fn transCPtrCast(...@@ -3936,11 +3936,26 @@ fn transCPtrCast(
3936}3936}
39373937
3938fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {3938fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
3939 // TODO use something more accurate than widening to a larger float type and printing that result
3939 switch (expr.getRawSemantics()) {3940 switch (expr.getRawSemantics()) {
3940 .IEEEhalf, // f163941 .IEEEhalf, // f16
3941 .IEEEsingle, // f323942 .IEEEsingle, // f32
3942 .IEEEdouble, // f643943 .IEEEdouble, // f64
3943 => {},3944 => {
3945 var dbl = expr.getValueAsApproximateDouble();
3946 const is_negative = dbl < 0; // -0.0 is considered non-negative
3947 if (is_negative) dbl = -dbl;
3948 const str = if (dbl == @floor(dbl))
3949 try std.fmt.allocPrint(c.arena, "{d}.0", .{dbl})
3950 else
3951 try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
3952 var node = try Tag.float_literal.create(c.arena, str);
3953 if (is_negative) node = try Tag.negate.create(c.arena, node);
3954 return maybeSuppressResult(c, used, node);
3955 },
3956 .x87DoubleExtended, // f80
3957 .IEEEquad, // f128
3958 => return transFloatingLiteralQuad(c, expr, used),
3944 else => |format| return fail(3959 else => |format| return fail(
3945 c,3960 c,
3946 error.UnsupportedTranslation,3961 error.UnsupportedTranslation,
...@@ -3949,14 +3964,44 @@ fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: R...@@ -3949,14 +3964,44 @@ fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: R
3949 .{format},3964 .{format},
3950 ),3965 ),
3951 }3966 }
3952 // TODO use something more accurate3967}
3953 var dbl = expr.getValueAsApproximateDouble();3968
3954 const is_negative = dbl < 0;3969fn transFloatingLiteralQuad(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
3955 if (is_negative) dbl = -dbl;3970 assert(switch (expr.getRawSemantics()) {
3956 const str = if (dbl == @floor(dbl))3971 .x87DoubleExtended, .IEEEquad => true,
3957 try std.fmt.allocPrint(c.arena, "{d}.0", .{dbl})3972 else => false,
3958 else3973 });
3959 try std.fmt.allocPrint(c.arena, "{d}", .{dbl});3974
3975 var low: u64 = undefined;
3976 var high: u64 = undefined;
3977 expr.getValueAsApproximateQuadBits(&low, &high);
3978 var quad: f128 = @bitCast(low | @as(u128, high) << 64);
3979 const is_negative = quad < 0; // -0.0 is considered non-negative
3980 if (is_negative) quad = -quad;
3981
3982 // TODO implement decimal format for f128 <https://github.com/ziglang/zig/issues/1181>
3983 // in the meantime, if the value can be roundtripped by casting it to f64, serializing it to
3984 // the decimal format and parsing it back as the exact same f128 value, then use that serialized form
3985 const str = fmt_decimal: {
3986 var buf: [512]u8 = undefined; // should be large enough to print any f64 in decimal form
3987 const dbl: f64 = @floatCast(quad);
3988 const temp_str = if (dbl == @floor(dbl))
3989 std.fmt.bufPrint(&buf, "{d}.0", .{dbl}) catch |err| switch (err) {
3990 error.NoSpaceLeft => unreachable,
3991 }
3992 else
3993 std.fmt.bufPrint(&buf, "{d}", .{dbl}) catch |err| switch (err) {
3994 error.NoSpaceLeft => unreachable,
3995 };
3996 const could_roundtrip = if (std.fmt.parseFloat(f128, temp_str)) |parsed_quad|
3997 quad == parsed_quad
3998 else |_|
3999 false;
4000 break :fmt_decimal if (could_roundtrip) try c.arena.dupe(u8, temp_str) else null;
4001 }
4002 // otherwise, fall back to the hexadecimal format
4003 orelse try std.fmt.allocPrint(c.arena, "{x}", .{quad});
4004
3960 var node = try Tag.float_literal.create(c.arena, str);4005 var node = try Tag.float_literal.create(c.arena, str);
3961 if (is_negative) node = try Tag.negate.create(c.arena, node);4006 if (is_negative) node = try Tag.negate.create(c.arena, node);
3962 return maybeSuppressResult(c, used, node);4007 return maybeSuppressResult(c, used, node);
src/zig_clang.cpp+11
...@@ -3245,6 +3245,17 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin...@@ -3245,6 +3245,17 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin
3245 return casted->getValueAsApproximateDouble();3245 return casted->getValueAsApproximateDouble();
3246}3246}
32473247
3248void ZigClangFloatingLiteral_getValueAsApproximateQuadBits(const ZigClangFloatingLiteral *self, uint64_t *low, uint64_t *high) {
3249 auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);
3250 llvm::APFloat apf = casted->getValue();
3251 bool ignored;
3252 apf.convert(llvm::APFloat::IEEEquad(), llvm::APFloat::rmNearestTiesToEven, &ignored);
3253 const llvm::APInt api = apf.bitcastToAPInt();
3254 const uint64_t *api_data = api.getRawData();
3255 *low = api_data[0];
3256 *high = api_data[1];
3257}
3258
3248struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *self) {3259struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *self) {
3249 auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);3260 auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);
3250 return bitcast(casted->getBeginLoc());3261 return bitcast(casted->getBeginLoc());
src/zig_clang.h+1
...@@ -1510,6 +1510,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st...@@ -1510,6 +1510,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st
1510ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST,1510ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST,
1511 unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM);1511 unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM);
1512ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self);1512ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self);
1513ZIG_EXTERN_C void ZigClangFloatingLiteral_getValueAsApproximateQuadBits(const ZigClangFloatingLiteral *self, uint64_t *low, uint64_t *high);
1513ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *);1514ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *);
1514ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self);1515ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self);
15151516
test/translate_c.zig+8-6
...@@ -1240,6 +1240,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1240,6 +1240,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1240 \\extern const float my_float = 1.0f;1240 \\extern const float my_float = 1.0f;
1241 \\extern const double my_double = 1.0;1241 \\extern const double my_double = 1.0;
1242 \\extern const long double my_longdouble = 1.0l;1242 \\extern const long double my_longdouble = 1.0l;
1243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
1243 , &([_][]const u8{1244 , &([_][]const u8{
1244 "pub const foo = @as(f32, 3.14);",1245 "pub const foo = @as(f32, 3.14);",
1245 "pub const bar = @as(c_longdouble, 16.0e-2);",1246 "pub const bar = @as(c_longdouble, 16.0e-2);",
...@@ -1250,13 +1251,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1250,13 +1251,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1250 "pub const foobar = -@as(c_longdouble, 73.0);",1251 "pub const foobar = -@as(c_longdouble, 73.0);",
1251 "pub export const my_float: f32 = 1.0;",1252 "pub export const my_float: f32 = 1.0;",
1252 "pub export const my_double: f64 = 1.0;",1253 "pub export const my_double: f64 = 1.0;",
1253 } ++ if (@bitSizeOf(c_longdouble) != 64) .{
1254 // TODO properly translate non-64-bit long doubles
1255 "source.h:10:42: warning: unsupported floating point constant format",
1256 "source.h:10:26: warning: unable to translate variable initializer, demoted to extern",
1257 "pub extern const my_longdouble: c_longdouble;",
1258 } else .{
1259 "pub export const my_longdouble: c_longdouble = 1.0;",1254 "pub export const my_longdouble: c_longdouble = 1.0;",
1255 switch (@bitSizeOf(c_longdouble)) {
1256 // TODO implement decimal format for f128 <https://github.com/ziglang/zig/issues/1181>
1257 // (so that f80/f128 values not exactly representable as f64 can be emitted in decimal form)
1258 80 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159ep0;",
1259 128 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159e05f1e2674d21p0;",
1260 else => "pub export const my_extended_precision_longdouble: c_longdouble = 1.0000000000000002;",
1261 },
1260 }));1262 }));
12611263
1262 cases.add("macro defines hexadecimal float",1264 cases.add("macro defines hexadecimal float",