mirror of
https://github.com/ziglang/zig.git
synced 2025-12-25 15:43:06 +00:00
Merge pull request #9468 from ehaas/translate-c-inf-nan
translate-c: handle NAN and INFINITY macros
This commit is contained in:
commit
f476463cd2
@ -191,6 +191,49 @@ pub inline fn __builtin_expect(expr: c_long, c: c_long) c_long {
|
||||
return expr;
|
||||
}
|
||||
|
||||
/// returns a quiet NaN. Quiet NaNs have many representations; tagp is used to select one in an
|
||||
/// implementation-defined way.
|
||||
/// This implementation is based on the description for __builtin_nan provided in the GCC docs at
|
||||
/// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fnan
|
||||
/// Comment is reproduced below:
|
||||
/// Since ISO C99 defines this function in terms of strtod, which we do not implement, a description
|
||||
/// of the parsing is in order.
|
||||
/// The string is parsed as by strtol; that is, the base is recognized by leading ‘0’ or ‘0x’ prefixes.
|
||||
/// The number parsed is placed in the significand such that the least significant bit of the number is
|
||||
/// at the least significant bit of the significand.
|
||||
/// The number is truncated to fit the significand field provided.
|
||||
/// The significand is forced to be a quiet NaN.
|
||||
///
|
||||
/// If tagp contains any non-numeric characters, the function returns a NaN whose significand is zero.
|
||||
/// If tagp is empty, the function returns a NaN whose significand is zero.
|
||||
pub inline fn __builtin_nanf(tagp: []const u8) f32 {
|
||||
const parsed = std.fmt.parseUnsigned(c_ulong, tagp, 0) catch 0;
|
||||
const bits = @truncate(u23, parsed); // single-precision float trailing significand is 23 bits
|
||||
return @bitCast(f32, @as(u32, bits) | std.math.qnan_u32);
|
||||
}
|
||||
|
||||
pub inline fn __builtin_huge_valf() f32 {
|
||||
return std.math.inf(f32);
|
||||
}
|
||||
|
||||
pub inline fn __builtin_inff() f32 {
|
||||
return std.math.inf(f32);
|
||||
}
|
||||
|
||||
pub inline fn __builtin_isnan(x: anytype) c_int {
|
||||
return @boolToInt(std.math.isNan(x));
|
||||
}
|
||||
|
||||
pub inline fn __builtin_isinf(x: anytype) c_int {
|
||||
return @boolToInt(std.math.isInf(x));
|
||||
}
|
||||
|
||||
/// Similar to isinf, except the return value is -1 for an argument of -Inf and 1 for an argument of +Inf.
|
||||
pub inline fn __builtin_isinf_sign(x: anytype) c_int {
|
||||
if (!std.math.isInf(x)) return 0;
|
||||
return if (std.math.isPositiveInf(x)) 1 else -1;
|
||||
}
|
||||
|
||||
// __builtin_alloca_with_align is not currently implemented.
|
||||
// It is used in a run-translated-c test and a test-translate-c test to ensure that non-implemented
|
||||
// builtins are correctly demoted. If you implement __builtin_alloca_with_align, please update the
|
||||
|
||||
@ -269,6 +269,11 @@ pub const CharacterLiteral = opaque {
|
||||
extern fn ZigClangCharacterLiteral_getValue(*const CharacterLiteral) c_uint;
|
||||
};
|
||||
|
||||
pub const ChooseExpr = opaque {
|
||||
pub const getChosenSubExpr = ZigClangChooseExpr_getChosenSubExpr;
|
||||
extern fn ZigClangChooseExpr_getChosenSubExpr(*const ChooseExpr) *const Expr;
|
||||
};
|
||||
|
||||
pub const CompoundAssignOperator = opaque {
|
||||
pub const getType = ZigClangCompoundAssignOperator_getType;
|
||||
extern fn ZigClangCompoundAssignOperator_getType(*const CompoundAssignOperator) QualType;
|
||||
|
||||
@ -1308,6 +1308,10 @@ fn transStmt(
|
||||
const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);
|
||||
return maybeSuppressResult(c, scope, result_used, shuffle_vec_node);
|
||||
},
|
||||
.ChooseExprClass => {
|
||||
const choose_expr = @ptrCast(*const clang.ChooseExpr, stmt);
|
||||
return transExpr(c, scope, choose_expr.getChosenSubExpr(), result_used);
|
||||
},
|
||||
// When adding new cases here, see comment for maybeBlockify()
|
||||
.GCCAsmStmtClass,
|
||||
.GotoStmtClass,
|
||||
@ -1969,7 +1973,7 @@ fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used:
|
||||
const node = try transExpr(c, scope, expr, used);
|
||||
if (node.castTag(.identifier)) |ident| {
|
||||
const name = ident.data;
|
||||
if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.c.builtins", .{name});
|
||||
if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.zig.c_builtins", .{name});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@ -5574,7 +5578,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
|
||||
.Identifier => {
|
||||
const mangled_name = scope.getAlias(slice);
|
||||
if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) {
|
||||
try m.fail(c, "TODO implement function '{s}' in std.c.builtins", .{mangled_name});
|
||||
try m.fail(c, "TODO implement function '{s}' in std.zig.c_builtins", .{mangled_name});
|
||||
return error.ParseError;
|
||||
}
|
||||
const identifier = try Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name);
|
||||
|
||||
@ -2832,6 +2832,11 @@ unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral
|
||||
return casted->getValue();
|
||||
}
|
||||
|
||||
const struct ZigClangExpr *ZigClangChooseExpr_getChosenSubExpr(const struct ZigClangChooseExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::ChooseExpr *>(self);
|
||||
return reinterpret_cast<const ZigClangExpr *>(casted->getChosenSubExpr());
|
||||
}
|
||||
|
||||
const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getCond(const struct ZigClangAbstractConditionalOperator *self) {
|
||||
auto casted = reinterpret_cast<const clang::AbstractConditionalOperator *>(self);
|
||||
return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
|
||||
|
||||
@ -104,6 +104,7 @@ struct ZigClangCStyleCastExpr;
|
||||
struct ZigClangCallExpr;
|
||||
struct ZigClangCaseStmt;
|
||||
struct ZigClangCharacterLiteral;
|
||||
struct ZigClangChooseExpr;
|
||||
struct ZigClangCompoundAssignOperator;
|
||||
struct ZigClangCompoundStmt;
|
||||
struct ZigClangConditionalOperator;
|
||||
@ -1242,6 +1243,8 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(
|
||||
ZIG_EXTERN_C enum ZigClangCharacterLiteral_CharacterKind ZigClangCharacterLiteral_getKind(const struct ZigClangCharacterLiteral *);
|
||||
ZIG_EXTERN_C unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral *);
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangChooseExpr_getChosenSubExpr(const struct ZigClangChooseExpr *);
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getCond(const struct ZigClangAbstractConditionalOperator *);
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getTrueExpr(const struct ZigClangAbstractConditionalOperator *);
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getFalseExpr(const struct ZigClangAbstractConditionalOperator *);
|
||||
|
||||
@ -1243,7 +1243,7 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\}
|
||||
, "");
|
||||
|
||||
// See __builtin_alloca_with_align comment in std.c.builtins
|
||||
// See __builtin_alloca_with_align comment in std.zig.c_builtins
|
||||
cases.add("use of unimplemented builtin in unused function does not prevent compilation",
|
||||
\\#include <stdlib.h>
|
||||
\\void unused() {
|
||||
@ -1659,4 +1659,54 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("__builtin_choose_expr (unchosen expression is not evaluated)",
|
||||
\\#include <stdlib.h>
|
||||
\\int main(void) {
|
||||
\\ int x = 0.0;
|
||||
\\ int y = 0.0;
|
||||
\\ int res;
|
||||
\\ res = __builtin_choose_expr(1, 1, x / y);
|
||||
\\ if (res != 1) abort();
|
||||
\\ res = __builtin_choose_expr(0, x / y, 2);
|
||||
\\ if (res != 2) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
// TODO: add isnan check for long double once bitfield support is added
|
||||
// (needed for x86_64-windows-gnu)
|
||||
// TODO: add isinf check for long double once std.math.isInf supports c_longdouble
|
||||
cases.add("NAN and INFINITY",
|
||||
\\#include <math.h>
|
||||
\\#include <stdint.h>
|
||||
\\#include <stdlib.h>
|
||||
\\union uf { uint32_t u; float f; };
|
||||
\\#define CHECK_NAN(STR, VAL) { \
|
||||
\\ union uf unpack = {.f = __builtin_nanf(STR)}; \
|
||||
\\ if (!isnan(unpack.f)) abort(); \
|
||||
\\ if (unpack.u != VAL) abort(); \
|
||||
\\}
|
||||
\\int main(void) {
|
||||
\\ float f_nan = NAN;
|
||||
\\ if (!isnan(f_nan)) abort();
|
||||
\\ double d_nan = NAN;
|
||||
\\ if (!isnan(d_nan)) abort();
|
||||
\\ CHECK_NAN("0", 0x7FC00000);
|
||||
\\ CHECK_NAN("", 0x7FC00000);
|
||||
\\ CHECK_NAN("1", 0x7FC00001);
|
||||
\\ CHECK_NAN("0x7FC00000", 0x7FC00000);
|
||||
\\ CHECK_NAN("0x7FC0000F", 0x7FC0000F);
|
||||
\\ CHECK_NAN("0x7FC000F0", 0x7FC000F0);
|
||||
\\ CHECK_NAN("0x7FC00F00", 0x7FC00F00);
|
||||
\\ CHECK_NAN("0x7FC0F000", 0x7FC0F000);
|
||||
\\ CHECK_NAN("0x7FCF0000", 0x7FCF0000);
|
||||
\\ CHECK_NAN("0xFFFFFFFF", 0x7FFFFFFF);
|
||||
\\ float f_inf = INFINITY;
|
||||
\\ if (!isinf(f_inf)) abort();
|
||||
\\ double d_inf = INFINITY;
|
||||
\\ if (!isinf(d_inf)) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
@ -3461,11 +3461,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
|
||||
});
|
||||
|
||||
// See __builtin_alloca_with_align comment in std.c.builtins
|
||||
// See __builtin_alloca_with_align comment in std.zig.c_builtins
|
||||
cases.add("demote un-implemented builtins",
|
||||
\\#define FOO(X) __builtin_alloca_with_align((X), 8)
|
||||
, &[_][]const u8{
|
||||
\\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.c.builtins");
|
||||
\\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.zig.c_builtins");
|
||||
});
|
||||
|
||||
cases.add("null sentinel arrays when initialized from string literal. Issue #8256",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user