authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-07-28 21:37:46+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-07-28 21:37:46+03:00
logf476463cd2552d384d0ef6f43f250b3abd45e4cd
treed4730eb7bec3d2554fd39872d7c445deceaba232
parenteb010ce65ddddb23ceddae86d377432cf1b2b01c
parentd4d3a9dcc93d517ffec43c9b4572977c05ee4d4b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9468 from ehaas/translate-c-inf-nan

translate-c: handle NAN and INFINITY macros

7 files changed, 115 insertions(+), 5 deletions(-)

lib/std/zig/c_builtins.zig+43
......@@ -191,6 +191,49 @@ pub inline fn __builtin_expect(expr: c_long, c: c_long) c_long {
191191 return expr;
192192}
193193
194/// returns a quiet NaN. Quiet NaNs have many representations; tagp is used to select one in an
195/// implementation-defined way.
196/// This implementation is based on the description for __builtin_nan provided in the GCC docs at
197/// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fnan
198/// Comment is reproduced below:
199/// Since ISO C99 defines this function in terms of strtod, which we do not implement, a description
200/// of the parsing is in order.
201/// The string is parsed as by strtol; that is, the base is recognized by leading ‘0’ or ‘0x’ prefixes.
202/// The number parsed is placed in the significand such that the least significant bit of the number is
203/// at the least significant bit of the significand.
204/// The number is truncated to fit the significand field provided.
205/// The significand is forced to be a quiet NaN.
206///
207/// If tagp contains any non-numeric characters, the function returns a NaN whose significand is zero.
208/// If tagp is empty, the function returns a NaN whose significand is zero.
209pub inline fn __builtin_nanf(tagp: []const u8) f32 {
210 const parsed = std.fmt.parseUnsigned(c_ulong, tagp, 0) catch 0;
211 const bits = @truncate(u23, parsed); // single-precision float trailing significand is 23 bits
212 return @bitCast(f32, @as(u32, bits) | std.math.qnan_u32);
213}
214
215pub inline fn __builtin_huge_valf() f32 {
216 return std.math.inf(f32);
217}
218
219pub inline fn __builtin_inff() f32 {
220 return std.math.inf(f32);
221}
222
223pub inline fn __builtin_isnan(x: anytype) c_int {
224 return @boolToInt(std.math.isNan(x));
225}
226
227pub inline fn __builtin_isinf(x: anytype) c_int {
228 return @boolToInt(std.math.isInf(x));
229}
230
231/// Similar to isinf, except the return value is -1 for an argument of -Inf and 1 for an argument of +Inf.
232pub inline fn __builtin_isinf_sign(x: anytype) c_int {
233 if (!std.math.isInf(x)) return 0;
234 return if (std.math.isPositiveInf(x)) 1 else -1;
235}
236
194237// __builtin_alloca_with_align is not currently implemented.
195238// It is used in a run-translated-c test and a test-translate-c test to ensure that non-implemented
196239// builtins are correctly demoted. If you implement __builtin_alloca_with_align, please update the
src/clang.zig+5
......@@ -269,6 +269,11 @@ pub const CharacterLiteral = opaque {
269269 extern fn ZigClangCharacterLiteral_getValue(*const CharacterLiteral) c_uint;
270270};
271271
272pub const ChooseExpr = opaque {
273 pub const getChosenSubExpr = ZigClangChooseExpr_getChosenSubExpr;
274 extern fn ZigClangChooseExpr_getChosenSubExpr(*const ChooseExpr) *const Expr;
275};
276
272277pub const CompoundAssignOperator = opaque {
273278 pub const getType = ZigClangCompoundAssignOperator_getType;
274279 extern fn ZigClangCompoundAssignOperator_getType(*const CompoundAssignOperator) QualType;
src/translate_c.zig+6-2
......@@ -1308,6 +1308,10 @@ fn transStmt(
13081308 const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);
13091309 return maybeSuppressResult(c, scope, result_used, shuffle_vec_node);
13101310 },
1311 .ChooseExprClass => {
1312 const choose_expr = @ptrCast(*const clang.ChooseExpr, stmt);
1313 return transExpr(c, scope, choose_expr.getChosenSubExpr(), result_used);
1314 },
13111315 // When adding new cases here, see comment for maybeBlockify()
13121316 .GCCAsmStmtClass,
13131317 .GotoStmtClass,
......@@ -1969,7 +1973,7 @@ fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used:
19691973 const node = try transExpr(c, scope, expr, used);
19701974 if (node.castTag(.identifier)) |ident| {
19711975 const name = ident.data;
1972 if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.c.builtins", .{name});
1976 if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.zig.c_builtins", .{name});
19731977 }
19741978 return node;
19751979}
......@@ -5574,7 +5578,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
55745578 .Identifier => {
55755579 const mangled_name = scope.getAlias(slice);
55765580 if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) {
5577 try m.fail(c, "TODO implement function '{s}' in std.c.builtins", .{mangled_name});
5581 try m.fail(c, "TODO implement function '{s}' in std.zig.c_builtins", .{mangled_name});
55785582 return error.ParseError;
55795583 }
55805584 const identifier = try Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name);
src/zig_clang.cpp+5
......@@ -2832,6 +2832,11 @@ unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral
28322832 return casted->getValue();
28332833}
28342834
2835const struct ZigClangExpr *ZigClangChooseExpr_getChosenSubExpr(const struct ZigClangChooseExpr *self) {
2836 auto casted = reinterpret_cast<const clang::ChooseExpr *>(self);
2837 return reinterpret_cast<const ZigClangExpr *>(casted->getChosenSubExpr());
2838}
2839
28352840const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getCond(const struct ZigClangAbstractConditionalOperator *self) {
28362841 auto casted = reinterpret_cast<const clang::AbstractConditionalOperator *>(self);
28372842 return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
src/zig_clang.h+3
......@@ -104,6 +104,7 @@ struct ZigClangCStyleCastExpr;
104104struct ZigClangCallExpr;
105105struct ZigClangCaseStmt;
106106struct ZigClangCharacterLiteral;
107struct ZigClangChooseExpr;
107108struct ZigClangCompoundAssignOperator;
108109struct ZigClangCompoundStmt;
109110struct ZigClangConditionalOperator;
......@@ -1242,6 +1243,8 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(
12421243ZIG_EXTERN_C enum ZigClangCharacterLiteral_CharacterKind ZigClangCharacterLiteral_getKind(const struct ZigClangCharacterLiteral *);
12431244ZIG_EXTERN_C unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral *);
12441245
1246ZIG_EXTERN_C const struct ZigClangExpr *ZigClangChooseExpr_getChosenSubExpr(const struct ZigClangChooseExpr *);
1247
12451248ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getCond(const struct ZigClangAbstractConditionalOperator *);
12461249ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getTrueExpr(const struct ZigClangAbstractConditionalOperator *);
12471250ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getFalseExpr(const struct ZigClangAbstractConditionalOperator *);
test/run_translated_c.zig+51-1
......@@ -1243,7 +1243,7 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
12431243 \\}
12441244 , "");
12451245
1246 // See __builtin_alloca_with_align comment in std.c.builtins
1246 // See __builtin_alloca_with_align comment in std.zig.c_builtins
12471247 cases.add("use of unimplemented builtin in unused function does not prevent compilation",
12481248 \\#include <stdlib.h>
12491249 \\void unused() {
......@@ -1659,4 +1659,54 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
16591659 \\ return 0;
16601660 \\}
16611661 , "");
1662
1663 cases.add("__builtin_choose_expr (unchosen expression is not evaluated)",
1664 \\#include <stdlib.h>
1665 \\int main(void) {
1666 \\ int x = 0.0;
1667 \\ int y = 0.0;
1668 \\ int res;
1669 \\ res = __builtin_choose_expr(1, 1, x / y);
1670 \\ if (res != 1) abort();
1671 \\ res = __builtin_choose_expr(0, x / y, 2);
1672 \\ if (res != 2) abort();
1673 \\ return 0;
1674 \\}
1675 , "");
1676
1677 // TODO: add isnan check for long double once bitfield support is added
1678 // (needed for x86_64-windows-gnu)
1679 // TODO: add isinf check for long double once std.math.isInf supports c_longdouble
1680 cases.add("NAN and INFINITY",
1681 \\#include <math.h>
1682 \\#include <stdint.h>
1683 \\#include <stdlib.h>
1684 \\union uf { uint32_t u; float f; };
1685 \\#define CHECK_NAN(STR, VAL) { \
1686 \\ union uf unpack = {.f = __builtin_nanf(STR)}; \
1687 \\ if (!isnan(unpack.f)) abort(); \
1688 \\ if (unpack.u != VAL) abort(); \
1689 \\}
1690 \\int main(void) {
1691 \\ float f_nan = NAN;
1692 \\ if (!isnan(f_nan)) abort();
1693 \\ double d_nan = NAN;
1694 \\ if (!isnan(d_nan)) abort();
1695 \\ CHECK_NAN("0", 0x7FC00000);
1696 \\ CHECK_NAN("", 0x7FC00000);
1697 \\ CHECK_NAN("1", 0x7FC00001);
1698 \\ CHECK_NAN("0x7FC00000", 0x7FC00000);
1699 \\ CHECK_NAN("0x7FC0000F", 0x7FC0000F);
1700 \\ CHECK_NAN("0x7FC000F0", 0x7FC000F0);
1701 \\ CHECK_NAN("0x7FC00F00", 0x7FC00F00);
1702 \\ CHECK_NAN("0x7FC0F000", 0x7FC0F000);
1703 \\ CHECK_NAN("0x7FCF0000", 0x7FCF0000);
1704 \\ CHECK_NAN("0xFFFFFFFF", 0x7FFFFFFF);
1705 \\ float f_inf = INFINITY;
1706 \\ if (!isinf(f_inf)) abort();
1707 \\ double d_inf = INFINITY;
1708 \\ if (!isinf(d_inf)) abort();
1709 \\ return 0;
1710 \\}
1711 , "");
16621712}
test/translate_c.zig+2-2
......@@ -3461,11 +3461,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
34613461 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
34623462 });
34633463
3464 // See __builtin_alloca_with_align comment in std.c.builtins
3464 // See __builtin_alloca_with_align comment in std.zig.c_builtins
34653465 cases.add("demote un-implemented builtins",
34663466 \\#define FOO(X) __builtin_alloca_with_align((X), 8)
34673467 , &[_][]const u8{
3468 \\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.c.builtins");
3468 \\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.zig.c_builtins");
34693469 });
34703470
34713471 cases.add("null sentinel arrays when initialized from string literal. Issue #8256",