| author | |
| committer | |
| log | ccdb81fb31f3fa1384b44b74ecdae345457bd0b5 |
| tree | e58de03181610a033949c2079b607336072af5a8 |
| parent | 6a75cfd0f6d45de3b4d1ad74eaec892dc1cd6e30 |
C compiler intrinsics can only appear as part of a function call. When called
they are implicitly cast to a function pointer; treat this as a non-null
pointer so that it emits as a regular Zig function call.
Put `pub usingnamespace @import("std").c.builtins;` at the top of translated
C files so that they will have access to builtin functions defined there.
Fixes #67074 files changed, 322 insertions(+), 4 deletions(-)
lib/std/c.zig+1| ... | ... | @@ -12,6 +12,7 @@ pub const Token = tokenizer.Token; |
| 12 | 12 | pub const Tokenizer = tokenizer.Tokenizer; |
| 13 | 13 | pub const parse = @import("c/parse.zig").parse; |
| 14 | 14 | pub const ast = @import("c/ast.zig"); |
| 15 | pub const builtins = @import("c/builtins.zig"); | |
| 15 | 16 | |
| 16 | 17 | test "" { |
| 17 | 18 | _ = tokenizer; |
lib/std/c/builtins.zig created+118| ... | ... | @@ -0,0 +1,118 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | ||
| 9 | pub inline fn __builtin_bswap16(val: u16) callconv(.C) u16 { return @byteSwap(u16, val); } | |
| 10 | pub inline fn __builtin_bswap32(val: u32) callconv(.C) u32 { return @byteSwap(u32, val); } | |
| 11 | pub inline fn __builtin_bswap64(val: u64) callconv(.C) u64 { return @byteSwap(u64, val); } | |
| 12 | ||
| 13 | pub inline fn __builtin_signbit(val: f64) callconv(.C) c_int { return @boolToInt(std.math.signbit(val)); } | |
| 14 | pub inline fn __builtin_signbitf(val: f32) callconv(.C) c_int { return @boolToInt(std.math.signbit(val)); } | |
| 15 | ||
| 16 | pub inline fn __builtin_popcount(val: c_uint) callconv(.C) c_int { | |
| 17 | // popcount of a c_uint will never exceed the capacity of a c_int | |
| 18 | @setRuntimeSafety(false); | |
| 19 | return @bitCast(c_int, @as(c_uint, @popCount(c_uint, val))); | |
| 20 | } | |
| 21 | pub inline fn __builtin_ctz(val: c_uint) callconv(.C) c_int { | |
| 22 | // Returns the number of trailing 0-bits in val, starting at the least significant bit position. | |
| 23 | // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint | |
| 24 | @setRuntimeSafety(false); | |
| 25 | return @bitCast(c_int, @as(c_uint, @ctz(c_uint, val))); | |
| 26 | } | |
| 27 | pub inline fn __builtin_clz(val: c_uint) callconv(.C) c_int { | |
| 28 | // Returns the number of leading 0-bits in x, starting at the most significant bit position. | |
| 29 | // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint | |
| 30 | @setRuntimeSafety(false); | |
| 31 | return @bitCast(c_int, @as(c_uint, @clz(c_uint, val))); | |
| 32 | } | |
| 33 | ||
| 34 | pub inline fn __builtin_sqrt(val: f64) callconv(.C) f64 { return @sqrt(val); } | |
| 35 | pub inline fn __builtin_sqrtf(val: f32) callconv(.C) f32 { return @sqrt(val); } | |
| 36 | ||
| 37 | pub inline fn __builtin_sin(val: f64) callconv(.C) f64 { return @sin(val); } | |
| 38 | pub inline fn __builtin_sinf(val: f32) callconv(.C) f32 { return @sin(val); } | |
| 39 | pub inline fn __builtin_cos(val: f64) callconv(.C) f64 { return @cos(val); } | |
| 40 | pub inline fn __builtin_cosf(val: f32) callconv(.C) f32 { return @cos(val); } | |
| 41 | ||
| 42 | pub inline fn __builtin_exp(val: f64) callconv(.C) f64 { return @exp(val); } | |
| 43 | pub inline fn __builtin_expf(val: f32) callconv(.C) f32 { return @exp(val); } | |
| 44 | pub inline fn __builtin_exp2(val: f64) callconv(.C) f64 { return @exp2(val); } | |
| 45 | pub inline fn __builtin_exp2f(val: f32) callconv(.C) f32 { return @exp2(val); } | |
| 46 | pub inline fn __builtin_log(val: f64) callconv(.C) f64 { return @log(val); } | |
| 47 | pub inline fn __builtin_logf(val: f32) callconv(.C) f32 { return @log(val); } | |
| 48 | pub inline fn __builtin_log2(val: f64) callconv(.C) f64 { return @log2(val); } | |
| 49 | pub inline fn __builtin_log2f(val: f32) callconv(.C) f32 { return @log2(val); } | |
| 50 | pub inline fn __builtin_log10(val: f64) callconv(.C) f64 { return @log10(val); } | |
| 51 | pub inline fn __builtin_log10f(val: f32) callconv(.C) f32 { return @log10(val); } | |
| 52 | ||
| 53 | // Standard C Library bug: The absolute value of the most negative integer remains negative. | |
| 54 | pub inline fn __builtin_abs(val: c_int) callconv(.C) c_int { return std.math.absInt(val) catch std.math.minInt(c_int); } | |
| 55 | pub inline fn __builtin_fabs(val: f64) callconv(.C) f64 { return @fabs(val); } | |
| 56 | pub inline fn __builtin_fabsf(val: f32) callconv(.C) f32 { return @fabs(val); } | |
| 57 | ||
| 58 | pub inline fn __builtin_floor(val: f64) callconv(.C) f64 { return @floor(val); } | |
| 59 | pub inline fn __builtin_floorf(val: f32) callconv(.C) f32 { return @floor(val); } | |
| 60 | pub inline fn __builtin_ceil(val: f64) callconv(.C) f64 { return @ceil(val); } | |
| 61 | pub inline fn __builtin_ceilf(val: f32) callconv(.C) f32 { return @ceil(val); } | |
| 62 | pub inline fn __builtin_trunc(val: f64) callconv(.C) f64 { return @trunc(val); } | |
| 63 | pub inline fn __builtin_truncf(val: f32) callconv(.C) f32 { return @trunc(val); } | |
| 64 | pub inline fn __builtin_round(val: f64) callconv(.C) f64 { return @round(val); } | |
| 65 | pub inline fn __builtin_roundf(val: f32) callconv(.C) f32 { return @round(val); } | |
| 66 | ||
| 67 | pub inline fn __builtin_strlen(s: [*c]const u8) callconv(.C) usize { return std.mem.lenZ(s); } | |
| 68 | pub inline fn __builtin_strcmp(s1: [*c]const u8, s2: [*c]const u8) callconv(.C) c_int { | |
| 69 | return @as(c_int, std.cstr.cmp(s1, s2)); | |
| 70 | } | |
| 71 | ||
| 72 | pub inline fn __builtin_object_size(ptr: ?*const c_void, ty: c_int) callconv(.C) usize { | |
| 73 | // clang semantics match gcc's: https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html | |
| 74 | // If it is not possible to determine which objects ptr points to at compile time, | |
| 75 | // __builtin_object_size should return (size_t) -1 for type 0 or 1 and (size_t) 0 | |
| 76 | // for type 2 or 3. | |
| 77 | if (ty == 0 or ty == 1) return @bitCast(usize, -@as(c_long, 1)); | |
| 78 | if (ty == 2 or ty == 3) return 0; | |
| 79 | unreachable; | |
| 80 | } | |
| 81 | ||
| 82 | pub inline fn __builtin___memset_chk( | |
| 83 | dst: ?*c_void, | |
| 84 | val: c_int, | |
| 85 | len: usize, | |
| 86 | remaining: usize, | |
| 87 | ) callconv(.C) ?*c_void { | |
| 88 | if (len > remaining) @panic("std.c.builtins.memset_chk called with len > remaining"); | |
| 89 | return __builtin_memset(dst, val, len); | |
| 90 | } | |
| 91 | ||
| 92 | pub inline fn __builtin_memset(dst: ?*c_void, val: c_int, len: usize) callconv(.C) ?*c_void { | |
| 93 | const dst_cast = @ptrCast([*c]u8, dst); | |
| 94 | @memset(dst_cast, @bitCast(u8, @truncate(i8, val)), len); | |
| 95 | return dst; | |
| 96 | } | |
| 97 | ||
| 98 | pub inline fn __builtin___memcpy_chk( | |
| 99 | noalias dst: ?*c_void, | |
| 100 | noalias src: ?*const c_void, | |
| 101 | len: usize, | |
| 102 | remaining: usize, | |
| 103 | ) callconv(.C) ?*c_void { | |
| 104 | if (len > remaining) @panic("std.c.builtins.memcpy_chk called with len > remaining"); | |
| 105 | return __builtin_memcpy(dst, src, len); | |
| 106 | } | |
| 107 | ||
| 108 | pub inline fn __builtin_memcpy( | |
| 109 | noalias dst: ?*c_void, | |
| 110 | noalias src: ?*const c_void, | |
| 111 | len: usize, | |
| 112 | ) callconv(.C) ?*c_void { | |
| 113 | const dst_cast = @ptrCast([*c]u8, dst); | |
| 114 | const src_cast = @ptrCast([*c]const u8, src); | |
| 115 | ||
| 116 | @memcpy(dst_cast, src_cast, len); | |
| 117 | return dst; | |
| 118 | } |
src/translate_c.zig+50-4| ... | ... | @@ -328,6 +328,47 @@ pub const Context = struct { |
| 328 | 328 | } |
| 329 | 329 | }; |
| 330 | 330 | |
| 331 | fn addCBuiltinsNamespace(c: *Context) Error!void { | |
| 332 | // pub usingnamespace @import("std").c.builtins; | |
| 333 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 334 | const use_tok = try appendToken(c, .Keyword_usingnamespace, "usingnamespace"); | |
| 335 | const import_tok = try appendToken(c, .Builtin, "@import"); | |
| 336 | const lparen_tok = try appendToken(c, .LParen, "("); | |
| 337 | const std_tok = try appendToken(c, .StringLiteral, "\"std\""); | |
| 338 | const rparen_tok = try appendToken(c, .RParen, ")"); | |
| 339 | ||
| 340 | const std_node = try c.arena.create(ast.Node.OneToken); | |
| 341 | std_node.* = .{ | |
| 342 | .base = .{ .tag = .StringLiteral }, | |
| 343 | .token = std_tok, | |
| 344 | }; | |
| 345 | ||
| 346 | const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1); | |
| 347 | call_node.* = .{ | |
| 348 | .builtin_token = import_tok, | |
| 349 | .params_len = 1, | |
| 350 | .rparen_token = rparen_tok, | |
| 351 | }; | |
| 352 | call_node.params()[0] = &std_node.base; | |
| 353 | ||
| 354 | var access_chain = &call_node.base; | |
| 355 | access_chain = try transCreateNodeFieldAccess(c, access_chain, "c"); | |
| 356 | access_chain = try transCreateNodeFieldAccess(c, access_chain, "builtins"); | |
| 357 | ||
| 358 | const semi_tok = try appendToken(c, .Semicolon, ";"); | |
| 359 | ||
| 360 | const bytes = try c.gpa.alignedAlloc(u8, @alignOf(ast.Node.Use), @sizeOf(ast.Node.Use)); | |
| 361 | const using_node = @ptrCast(*ast.Node.Use, bytes.ptr); | |
| 362 | using_node.* = .{ | |
| 363 | .doc_comments = null, | |
| 364 | .visib_token = pub_tok, | |
| 365 | .use_token = use_tok, | |
| 366 | .expr = access_chain, | |
| 367 | .semicolon_token = semi_tok, | |
| 368 | }; | |
| 369 | try c.root_decls.append(c.gpa, &using_node.base); | |
| 370 | } | |
| 371 | ||
| 331 | 372 | pub fn translate( |
| 332 | 373 | gpa: *mem.Allocator, |
| 333 | 374 | args_begin: [*]?[*]const u8, |
| ... | ... | @@ -377,6 +418,8 @@ pub fn translate( |
| 377 | 418 | context.opaque_demotes.deinit(gpa); |
| 378 | 419 | } |
| 379 | 420 | |
| 421 | try addCBuiltinsNamespace(&context); | |
| 422 | ||
| 380 | 423 | try prepopulateGlobalNameTable(ast_unit, &context); |
| 381 | 424 | |
| 382 | 425 | if (!ast_unit.visitLocalTopLevelDecls(&context, declVisitorC)) { |
| ... | ... | @@ -1726,6 +1769,9 @@ fn transImplicitCastExpr( |
| 1726 | 1769 | const rhs_node = try transCreateNodeInt(rp.c, 0); |
| 1727 | 1770 | return transCreateNodeInfixOp(rp, scope, sub_expr_node, .BangEqual, op_token, rhs_node, result_used, false); |
| 1728 | 1771 | }, |
| 1772 | .BuiltinFnToFnPtr => { | |
| 1773 | return transExpr(rp, scope, sub_expr, .used, .r_value); | |
| 1774 | }, | |
| 1729 | 1775 | else => |kind| return revertAndWarn( |
| 1730 | 1776 | rp, |
| 1731 | 1777 | error.UnsupportedTranslation, |
| ... | ... | @@ -2028,7 +2074,6 @@ fn transCCast( |
| 2028 | 2074 | // 1. If src_type is an enum, determine the underlying signed int type |
| 2029 | 2075 | // 2. Extend or truncate without changing signed-ness. |
| 2030 | 2076 | // 3. Bit-cast to correct signed-ness |
| 2031 | ||
| 2032 | 2077 | const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type); |
| 2033 | 2078 | const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type); |
| 2034 | 2079 | const src_int_expr = if (cIsInteger(src_type)) expr else try transEnumToInt(rp.c, expr); |
| ... | ... | @@ -3048,8 +3093,9 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, r |
| 3048 | 3093 | const fn_expr = if (is_ptr and fn_ty != null) blk: { |
| 3049 | 3094 | if (callee.getStmtClass() == .ImplicitCastExprClass) { |
| 3050 | 3095 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, callee); |
| 3051 | ||
| 3052 | if (implicit_cast.getCastKind() == .FunctionToPointerDecay) { | |
| 3096 | const cast_kind = implicit_cast.getCastKind(); | |
| 3097 | if (cast_kind == .BuiltinFnToFnPtr) break :blk raw_fn_expr; | |
| 3098 | if (cast_kind == .FunctionToPointerDecay) { | |
| 3053 | 3099 | const subexpr = implicit_cast.getSubExpr(); |
| 3054 | 3100 | if (subexpr.getStmtClass() == .DeclRefExprClass) { |
| 3055 | 3101 | const decl_ref = @ptrCast(*const clang.DeclRefExpr, subexpr); |
| ... | ... | @@ -5881,7 +5927,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!* |
| 5881 | 5927 | return error.ParseError; |
| 5882 | 5928 | } |
| 5883 | 5929 | |
| 5884 | const ident_token = try appendTokenFmt(c, .Identifier, "{}_{}", .{slice, m.slice()}); | |
| 5930 | const ident_token = try appendTokenFmt(c, .Identifier, "{}_{}", .{ slice, m.slice() }); | |
| 5885 | 5931 | const identifier = try c.arena.create(ast.Node.OneToken); |
| 5886 | 5932 | identifier.* = .{ |
| 5887 | 5933 | .base = .{ .tag = .Identifier }, |
test/run_translated_c.zig+153| ... | ... | @@ -491,4 +491,157 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 491 | 491 | \\ return 0; |
| 492 | 492 | \\} |
| 493 | 493 | , ""); |
| 494 | ||
| 495 | cases.add("issue #6707 cast builtin call result to opaque struct pointer", | |
| 496 | \\#include <stdlib.h> | |
| 497 | \\struct foo* make_foo(void) | |
| 498 | \\{ | |
| 499 | \\ return (struct foo*)__builtin_strlen("0123456789ABCDEF"); | |
| 500 | \\} | |
| 501 | \\int main(void) { | |
| 502 | \\ struct foo *foo_pointer = make_foo(); | |
| 503 | \\ if (foo_pointer != (struct foo*)16) abort(); | |
| 504 | \\ return 0; | |
| 505 | \\} | |
| 506 | , ""); | |
| 507 | ||
| 508 | cases.add("C built-ins", | |
| 509 | \\#include <stdlib.h> | |
| 510 | \\#include <limits.h> | |
| 511 | \\#include <stdbool.h> | |
| 512 | \\#define M_E 2.71828182845904523536 | |
| 513 | \\#define M_PI_2 1.57079632679489661923 | |
| 514 | \\bool check_clz(unsigned int pos) { | |
| 515 | \\ return (__builtin_clz(1 << pos) == (8 * sizeof(unsigned int) - pos - 1)); | |
| 516 | \\} | |
| 517 | \\int main(void) { | |
| 518 | \\ if (__builtin_bswap16(0x0102) != 0x0201) abort(); | |
| 519 | \\ if (__builtin_bswap32(0x01020304) != 0x04030201) abort(); | |
| 520 | \\ if (__builtin_bswap64(0x0102030405060708) != 0x0807060504030201) abort(); | |
| 521 | \\ | |
| 522 | \\ if (__builtin_signbit(0.0) != 0) abort(); | |
| 523 | \\ if (__builtin_signbitf(0.0f) != 0) abort(); | |
| 524 | \\ if (__builtin_signbit(1.0) != 0) abort(); | |
| 525 | \\ if (__builtin_signbitf(1.0f) != 0) abort(); | |
| 526 | \\ if (__builtin_signbit(-1.0) != 1) abort(); | |
| 527 | \\ if (__builtin_signbitf(-1.0f) != 1) abort(); | |
| 528 | \\ | |
| 529 | \\ if (__builtin_popcount(0) != 0) abort(); | |
| 530 | \\ if (__builtin_popcount(0b1) != 1) abort(); | |
| 531 | \\ if (__builtin_popcount(0b11) != 2) abort(); | |
| 532 | \\ if (__builtin_popcount(0b1111) != 4) abort(); | |
| 533 | \\ if (__builtin_popcount(0b11111111) != 8) abort(); | |
| 534 | \\ | |
| 535 | \\ if (__builtin_ctz(0b1) != 0) abort(); | |
| 536 | \\ if (__builtin_ctz(0b10) != 1) abort(); | |
| 537 | \\ if (__builtin_ctz(0b100) != 2) abort(); | |
| 538 | \\ if (__builtin_ctz(0b10000) != 4) abort(); | |
| 539 | \\ if (__builtin_ctz(0b100000000) != 8) abort(); | |
| 540 | \\ | |
| 541 | \\ if (!check_clz(0)) abort(); | |
| 542 | \\ if (!check_clz(1)) abort(); | |
| 543 | \\ if (!check_clz(2)) abort(); | |
| 544 | \\ if (!check_clz(4)) abort(); | |
| 545 | \\ if (!check_clz(8)) abort(); | |
| 546 | \\ | |
| 547 | \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256))) != 2.0) abort(); | |
| 548 | \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0))) != 2.0) abort(); | |
| 549 | \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0f))) != 2.0) abort(); | |
| 550 | \\ if (__builtin_sqrtf(__builtin_sqrtf(__builtin_sqrtf(256.0f))) != 2.0f) abort(); | |
| 551 | \\ | |
| 552 | \\ if (__builtin_sin(1.0) != -__builtin_sin(-1.0)) abort(); | |
| 553 | \\ if (__builtin_sinf(1.0f) != -__builtin_sinf(-1.0f)) abort(); | |
| 554 | \\ if (__builtin_sin(M_PI_2) != 1.0) abort(); | |
| 555 | \\ if (__builtin_sinf(M_PI_2) != 1.0f) abort(); | |
| 556 | \\ | |
| 557 | \\ if (__builtin_cos(1.0) != __builtin_cos(-1.0)) abort(); | |
| 558 | \\ if (__builtin_cosf(1.0f) != __builtin_cosf(-1.0f)) abort(); | |
| 559 | \\ if (__builtin_cos(0.0) != 1.0) abort(); | |
| 560 | \\ if (__builtin_cosf(0.0f) != 1.0f) abort(); | |
| 561 | \\ | |
| 562 | \\ if (__builtin_exp(0) != 1.0) abort(); | |
| 563 | \\ if (__builtin_fabs(__builtin_exp(1.0) - M_E) > 0.00000001) abort(); | |
| 564 | \\ if (__builtin_exp(0.0f) != 1.0f) abort(); | |
| 565 | \\ | |
| 566 | \\ if (__builtin_exp2(0) != 1.0) abort(); | |
| 567 | \\ if (__builtin_exp2(4.0) != 16.0) abort(); | |
| 568 | \\ if (__builtin_exp2f(0.0f) != 1.0f) abort(); | |
| 569 | \\ if (__builtin_exp2f(4.0f) != 16.0f) abort(); | |
| 570 | \\ | |
| 571 | \\ if (__builtin_log(M_E) != 1.0) abort(); | |
| 572 | \\ if (__builtin_log(1.0) != 0.0) abort(); | |
| 573 | \\ if (__builtin_logf(1.0f) != 0.0f) abort(); | |
| 574 | \\ | |
| 575 | \\ if (__builtin_log2(8.0) != 3.0) abort(); | |
| 576 | \\ if (__builtin_log2(1.0) != 0.0) abort(); | |
| 577 | \\ if (__builtin_log2f(8.0f) != 3.0f) abort(); | |
| 578 | \\ if (__builtin_log2f(1.0f) != 0.0f) abort(); | |
| 579 | \\ | |
| 580 | \\ if (__builtin_log10(1000.0) != 3.0) abort(); | |
| 581 | \\ if (__builtin_log10(1.0) != 0.0) abort(); | |
| 582 | \\ if (__builtin_log10f(1000.0f) != 3.0f) abort(); | |
| 583 | \\ if (__builtin_log10f(1.0f) != 0.0f) abort(); | |
| 584 | \\ | |
| 585 | \\ if (__builtin_fabs(-42.0f) != 42.0) abort(); | |
| 586 | \\ if (__builtin_fabs(-42.0) != 42.0) abort(); | |
| 587 | \\ if (__builtin_fabs(-42) != 42.0) abort(); | |
| 588 | \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort(); | |
| 589 | \\ | |
| 590 | \\ if (__builtin_fabs(-42.0f) != 42.0) abort(); | |
| 591 | \\ if (__builtin_fabs(-42.0) != 42.0) abort(); | |
| 592 | \\ if (__builtin_fabs(-42) != 42.0) abort(); | |
| 593 | \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort(); | |
| 594 | \\ | |
| 595 | \\ if (__builtin_abs(42) != 42) abort(); | |
| 596 | \\ if (__builtin_abs(-42) != 42) abort(); | |
| 597 | \\ if (__builtin_abs(INT_MIN) != INT_MIN) abort(); | |
| 598 | \\ | |
| 599 | \\ if (__builtin_floor(42.9) != 42.0) abort(); | |
| 600 | \\ if (__builtin_floor(-42.9) != -43.0) abort(); | |
| 601 | \\ if (__builtin_floorf(42.9f) != 42.0f) abort(); | |
| 602 | \\ if (__builtin_floorf(-42.9f) != -43.0f) abort(); | |
| 603 | \\ | |
| 604 | \\ if (__builtin_ceil(42.9) != 43.0) abort(); | |
| 605 | \\ if (__builtin_ceil(-42.9) != -42) abort(); | |
| 606 | \\ if (__builtin_ceilf(42.9f) != 43.0f) abort(); | |
| 607 | \\ if (__builtin_ceilf(-42.9f) != -42.0f) abort(); | |
| 608 | \\ | |
| 609 | \\ if (__builtin_trunc(42.9) != 42.0) abort(); | |
| 610 | \\ if (__builtin_truncf(42.9f) != 42.0f) abort(); | |
| 611 | \\ if (__builtin_trunc(-42.9) != -42.0) abort(); | |
| 612 | \\ if (__builtin_truncf(-42.9f) != -42.0f) abort(); | |
| 613 | \\ | |
| 614 | \\ if (__builtin_round(0.5) != 1.0) abort(); | |
| 615 | \\ if (__builtin_round(-0.5) != -1.0) abort(); | |
| 616 | \\ if (__builtin_roundf(0.5f) != 1.0f) abort(); | |
| 617 | \\ if (__builtin_roundf(-0.5f) != -1.0f) abort(); | |
| 618 | \\ | |
| 619 | \\ if (__builtin_strcmp("abc", "abc") != 0) abort(); | |
| 620 | \\ if (__builtin_strcmp("abc", "def") >= 0 ) abort(); | |
| 621 | \\ if (__builtin_strcmp("def", "abc") <= 0) abort(); | |
| 622 | \\ | |
| 623 | \\ if (__builtin_strlen("this is a string") != 16) abort(); | |
| 624 | \\ | |
| 625 | \\ char *s = malloc(6); | |
| 626 | \\ __builtin_memcpy(s, "hello", 5); | |
| 627 | \\ s[5] = '\0'; | |
| 628 | \\ if (__builtin_strlen(s) != 5) abort(); | |
| 629 | \\ | |
| 630 | \\ __builtin_memset(s, 42, __builtin_strlen(s)); | |
| 631 | \\ if (s[0] != 42 || s[1] != 42 || s[2] != 42 || s[3] != 42 || s[4] != 42) abort(); | |
| 632 | \\ | |
| 633 | \\ free(s); | |
| 634 | \\ | |
| 635 | \\ return 0; | |
| 636 | \\} | |
| 637 | , ""); | |
| 638 | ||
| 639 | cases.add("function macro that uses builtin", | |
| 640 | \\#include <stdlib.h> | |
| 641 | \\#define FOO(x, y) (__builtin_popcount((x)) + __builtin_strlen((y))) | |
| 642 | \\int main() { | |
| 643 | \\ if (FOO(7, "hello!") != 9) abort(); | |
| 644 | \\ return 0; | |
| 645 | \\} | |
| 646 | , ""); | |
| 494 | 647 | } |