| author | |
| committer | |
| log | 8bf4b3c611b39fc39bad2a6c657541fa13973dea |
| tree | 663c8227fe167c7ad189162d7337e49bf22a747f |
| parent | 40bd93e2a24e3bdebd4f6454cfcffc51e5aaeeae |
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; |
| 508 | 508 | ||
| 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; |
| 511 | 514 |
src/translate_c.zig+54-9| ... | @@ -3936,11 +3936,26 @@ fn transCPtrCast( | ... | @@ -3936,11 +3936,26 @@ fn transCPtrCast( |
| 3936 | } | 3936 | } |
| 3937 | 3937 | ||
| 3938 | fn transFloatingLiteral(c: *Context, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { | 3938 | fn 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, // f16 | 3941 | .IEEEhalf, // f16 |
| 3941 | .IEEEsingle, // f32 | 3942 | .IEEEsingle, // f32 |
| 3942 | .IEEEdouble, // f64 | 3943 | .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 accurate | 3967 | } |
| 3953 | var dbl = expr.getValueAsApproximateDouble(); | 3968 | |
| 3954 | const is_negative = dbl < 0; | 3969 | fn 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 | else | 3973 | }); |
| 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 | } |
| 3247 | 3247 | ||
| 3248 | void 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 | |||
| 3248 | struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *self) { | 3259 | struct 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 |
| 1510 | ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, | 1510 | ZIG_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); |
| 1512 | ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); | 1512 | ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); |
| 1513 | ZIG_EXTERN_C void ZigClangFloatingLiteral_getValueAsApproximateQuadBits(const ZigClangFloatingLiteral *self, uint64_t *low, uint64_t *high); | ||
| 1513 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *); | 1514 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFloatingLiteral_getBeginLoc(const struct ZigClangFloatingLiteral *); |
| 1514 | ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self); | 1515 | ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self); |
| 1515 | 1516 |
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 | })); |
| 1261 | 1263 | ||
| 1262 | cases.add("macro defines hexadecimal float", | 1264 | cases.add("macro defines hexadecimal float", |