authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-12 16:44:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-16 13:55:26-07:00
log03ed0f0d2847a99823ee4ae1b1a0554b88c6544a
tree142640be85ddd378ef630e2ff4be368efa2fe2f3
parenta5ea22d0693cf767fa47c9947399651ed3c35aaf

C backend: implement overflow arithmetic

Most of the work here was additions to zig.h. The lowering code is mainly responsible for calling the correct function name depending on the operand type. Some of the compiler-rt calls here are not implemented yet and are non-standard symbols due to the C programming language not needing them. After this commit, the behavior tests with -ofmt=c are passing again.

3 files changed, 940 insertions(+), 84 deletions(-)

lib/std/builtin.zig+1-2
......@@ -767,8 +767,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
767767
768768 // Until self-hosted catches up with stage1 language features, we have a simpler
769769 // default panic function:
770 if ((builtin.zig_backend == .stage2_llvm and builtin.link_libc) or
771 builtin.zig_backend == .stage2_c or
770 if (builtin.zig_backend == .stage2_c or
772771 builtin.zig_backend == .stage2_wasm or
773772 builtin.zig_backend == .stage2_arm or
774773 builtin.zig_backend == .stage2_aarch64 or
src/codegen/c.zig+118-82
......@@ -1766,10 +1766,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17661766
17671767 .mul_add => try airMulAdd(f, inst),
17681768
1769 .add_with_overflow => try airAddWithOverflow(f, inst),
1770 .sub_with_overflow => try airSubWithOverflow(f, inst),
1771 .mul_with_overflow => try airMulWithOverflow(f, inst),
1772 .shl_with_overflow => try airShlWithOverflow(f, inst),
1769 .add_with_overflow => try airOverflow(f, inst, "addo_"),
1770 .sub_with_overflow => try airOverflow(f, inst, "subo_"),
1771 .mul_with_overflow => try airOverflow(f, inst, "mulo_"),
1772 .shl_with_overflow => try airOverflow(f, inst, "shlo_"),
17731773
17741774 .min => try airMinMax(f, inst, "<"),
17751775 .max => try airMinMax(f, inst, ">"),
......@@ -2295,7 +2295,8 @@ fn airWrapOp(
22952295
22962296 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
22972297 const inst_ty = f.air.typeOfIndex(inst);
2298 const int_info = inst_ty.intInfo(f.object.dg.module.getTarget());
2298 const target = f.object.dg.module.getTarget();
2299 const int_info = inst_ty.intInfo(target);
22992300 const bits = int_info.bits;
23002301
23012302 // if it's an unsigned int with non-arbitrary bit size then we can just add
......@@ -2313,47 +2314,8 @@ fn airWrapOp(
23132314 return f.fail("TODO: C backend: airWrapOp for large integers", .{});
23142315 }
23152316
2316 var min_buf: [80]u8 = undefined;
2317 const min = switch (int_info.signedness) {
2318 .unsigned => "0",
2319 else => switch (inst_ty.tag()) {
2320 .c_short => "SHRT_MIN",
2321 .c_int => "INT_MIN",
2322 .c_long => "LONG_MIN",
2323 .c_longlong => "LLONG_MIN",
2324 .isize => "INTPTR_MIN",
2325 else => blk: {
2326 const val = -1 * std.math.pow(i64, 2, @intCast(i64, bits - 1));
2327 break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) {
2328 error.NoSpaceLeft => unreachable,
2329 };
2330 },
2331 },
2332 };
2333
23342317 var max_buf: [80]u8 = undefined;
2335 const max = switch (inst_ty.tag()) {
2336 .c_short => "SHRT_MAX",
2337 .c_ushort => "USHRT_MAX",
2338 .c_int => "INT_MAX",
2339 .c_uint => "UINT_MAX",
2340 .c_long => "LONG_MAX",
2341 .c_ulong => "ULONG_MAX",
2342 .c_longlong => "LLONG_MAX",
2343 .c_ulonglong => "ULLONG_MAX",
2344 .isize => "INTPTR_MAX",
2345 .usize => "UINTPTR_MAX",
2346 else => blk: {
2347 const pow_bits = switch (int_info.signedness) {
2348 .signed => bits - 1,
2349 .unsigned => bits,
2350 };
2351 const val = std.math.pow(u64, 2, pow_bits) - 1;
2352 break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) {
2353 error.NoSpaceLeft => unreachable,
2354 };
2355 },
2356 };
2318 const max = intMax(inst_ty, target, &max_buf);
23572319
23582320 const lhs = try f.resolveInst(bin_op.lhs);
23592321 const rhs = try f.resolveInst(bin_op.rhs);
......@@ -2369,10 +2331,7 @@ fn airWrapOp(
23692331 .c_long => try w.writeAll("long"),
23702332 .c_longlong => try w.writeAll("longlong"),
23712333 else => {
2372 const prefix_byte: u8 = switch (int_info.signedness) {
2373 .signed => 'i',
2374 .unsigned => 'u',
2375 };
2334 const prefix_byte: u8 = signAbbrev(int_info.signedness);
23762335 for ([_]u8{ 8, 16, 32, 64 }) |nbits| {
23772336 if (bits <= nbits) {
23782337 try w.print("{c}{d}", .{ prefix_byte, nbits });
......@@ -2390,6 +2349,9 @@ fn airWrapOp(
23902349 try f.writeCValue(w, rhs);
23912350
23922351 if (int_info.signedness == .signed) {
2352 var min_buf: [80]u8 = undefined;
2353 const min = intMin(inst_ty, target, &min_buf);
2354
23932355 try w.print(", {s}", .{min});
23942356 }
23952357
......@@ -2475,10 +2437,7 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
24752437 .c_long => try w.writeAll("long"),
24762438 .c_longlong => try w.writeAll("longlong"),
24772439 else => {
2478 const prefix_byte: u8 = switch (int_info.signedness) {
2479 .signed => 'i',
2480 .unsigned => 'u',
2481 };
2440 const prefix_byte: u8 = signAbbrev(int_info.signedness);
24822441 for ([_]u8{ 8, 16, 32, 64 }) |nbits| {
24832442 if (bits <= nbits) {
24842443 try w.print("{c}{d}", .{ prefix_byte, nbits });
......@@ -2505,28 +2464,63 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
25052464 return ret;
25062465}
25072466
2508fn airAddWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
2509 _ = f;
2510 _ = inst;
2511 return f.fail("TODO add with overflow", .{});
2512}
2467fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CValue {
2468 if (f.liveness.isUnused(inst))
2469 return CValue.none;
25132470
2514fn airSubWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
2515 _ = f;
2516 _ = inst;
2517 return f.fail("TODO sub with overflow", .{});
2518}
2471 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
2472 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
25192473
2520fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
2521 _ = f;
2522 _ = inst;
2523 return f.fail("TODO mul with overflow", .{});
2524}
2474 const lhs = try f.resolveInst(bin_op.lhs);
2475 const rhs = try f.resolveInst(bin_op.rhs);
25252476
2526fn airShlWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
2527 _ = f;
2528 _ = inst;
2529 return f.fail("TODO shl with overflow", .{});
2477 const inst_ty = f.air.typeOfIndex(inst);
2478 const scalar_ty = f.air.typeOf(bin_op.lhs).scalarType();
2479 const target = f.object.dg.module.getTarget();
2480 const int_info = scalar_ty.intInfo(target);
2481 const w = f.object.writer();
2482 const c_bits = toCIntBits(int_info.bits) orelse
2483 return f.fail("TODO: C backend: implement integer arithmetic larger than 128 bits", .{});
2484
2485 var max_buf: [80]u8 = undefined;
2486 const max = intMax(scalar_ty, target, &max_buf);
2487
2488 const ret = try f.allocLocal(inst_ty, .Mut);
2489 try w.writeAll(";");
2490 try f.object.indent_writer.insertNewline();
2491 try f.writeCValue(w, ret);
2492
2493 switch (int_info.signedness) {
2494 .unsigned => {
2495 try w.print(".field_1 = zig_{s}u{d}(", .{
2496 op_abbrev, c_bits,
2497 });
2498 try f.writeCValue(w, lhs);
2499 try w.writeAll(", ");
2500 try f.writeCValue(w, rhs);
2501 try w.writeAll(", &");
2502 try f.writeCValue(w, ret);
2503 try w.print(".field_0, {s}", .{max});
2504 },
2505 .signed => {
2506 var min_buf: [80]u8 = undefined;
2507 const min = intMin(scalar_ty, target, &min_buf);
2508
2509 try w.print(".field_1 = zig_{s}i{d}(", .{
2510 op_abbrev, c_bits,
2511 });
2512 try f.writeCValue(w, lhs);
2513 try w.writeAll(", ");
2514 try f.writeCValue(w, rhs);
2515 try w.writeAll(", &");
2516 try f.writeCValue(w, ret);
2517 try w.print(".field_0, {s}, {s}", .{ min, max });
2518 },
2519 }
2520
2521 try w.writeAll(");");
2522 try f.object.indent_writer.insertNewline();
2523 return ret;
25302524}
25312525
25322526fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3571,11 +3565,7 @@ fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !C
35713565 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
35723566
35733567 try writer.print(" = zig_{s}_", .{fn_name});
3574 const prefix_byte: u8 = switch (int_info.signedness) {
3575 .signed => 'i',
3576 .unsigned => 'u',
3577 };
3578 try writer.print("{c}{d}(", .{ prefix_byte, c_bits });
3568 try writer.print("{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
35793569 try f.writeCValue(writer, try f.resolveInst(operand));
35803570 try writer.print(", {d});\n", .{int_info.bits});
35813571 return local;
......@@ -3596,11 +3586,7 @@ fn airBinOpBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u
35963586 const int_info = lhs_ty.intInfo(target);
35973587 const c_bits = toCIntBits(int_info.bits) orelse
35983588 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
3599 const prefix_byte: u8 = switch (int_info.signedness) {
3600 .signed => 'i',
3601 .unsigned => 'u',
3602 };
3603 try writer.print(" = zig_{s}_{c}{d}", .{ fn_name, prefix_byte, c_bits });
3589 try writer.print(" = zig_{s}_{c}{d}", .{ fn_name, signAbbrev(int_info.signedness), c_bits });
36043590 } else if (lhs_ty.isRuntimeFloat()) {
36053591 const c_bits = lhs_ty.floatBits(target);
36063592 try writer.print(" = zig_{s}_f{d}", .{ fn_name, c_bits });
......@@ -4085,3 +4071,53 @@ fn toCIntBits(zig_bits: u32) ?u32 {
40854071 }
40864072 return null;
40874073}
4074
4075fn signAbbrev(signedness: std.builtin.Signedness) u8 {
4076 return switch (signedness) {
4077 .signed => 'i',
4078 .unsigned => 'u',
4079 };
4080}
4081
4082fn intMax(ty: Type, target: std.Target, buf: []u8) []const u8 {
4083 switch (ty.tag()) {
4084 .c_short => return "SHRT_MAX",
4085 .c_ushort => return "USHRT_MAX",
4086 .c_int => return "INT_MAX",
4087 .c_uint => return "UINT_MAX",
4088 .c_long => return "LONG_MAX",
4089 .c_ulong => return "ULONG_MAX",
4090 .c_longlong => return "LLONG_MAX",
4091 .c_ulonglong => return "ULLONG_MAX",
4092 else => {
4093 const int_info = ty.intInfo(target);
4094 const rhs = @intCast(u7, int_info.bits - @boolToInt(int_info.signedness == .signed));
4095 const val = (@as(u128, 1) << rhs) - 1;
4096 // TODO make this integer literal have a suffix if necessary (such as "ull")
4097 return std.fmt.bufPrint(buf, "{}", .{val}) catch |err| switch (err) {
4098 error.NoSpaceLeft => unreachable,
4099 };
4100 },
4101 }
4102}
4103
4104fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {
4105 switch (ty.tag()) {
4106 .c_short => return "SHRT_MIN",
4107 .c_int => return "INT_MIN",
4108 .c_long => return "LONG_MIN",
4109 .c_longlong => return "LLONG_MIN",
4110 else => {
4111 const int_info = ty.intInfo(target);
4112 assert(int_info.signedness == .signed);
4113 const val = v: {
4114 if (int_info.bits == 0) break :v 0;
4115 const rhs = @intCast(u7, (int_info.bits - 1));
4116 break :v -(@as(i128, 1) << rhs);
4117 };
4118 return std.fmt.bufPrint(buf, "{d}", .{val}) catch |err| switch (err) {
4119 error.NoSpaceLeft => unreachable,
4120 };
4121 },
4122 }
4123}
src/link/C/zig.h+821
......@@ -165,8 +165,24 @@
165165
166166#define int128_t __int128
167167#define uint128_t unsigned __int128
168#define UINT128_MAX ((uint128_t)(0xffffffffffffffffull) | 0xffffffffffffffffull)
168169ZIG_EXTERN_C void *memcpy (void *ZIG_RESTRICT, const void *ZIG_RESTRICT, size_t);
169170ZIG_EXTERN_C void *memset (void *, int, size_t);
171ZIG_EXTERN_C int64_t __addodi4(int64_t lhs, int64_t rhs, int *overflow);
172ZIG_EXTERN_C int128_t __addoti4(int128_t lhs, int128_t rhs, int *overflow);
173ZIG_EXTERN_C uint64_t __uaddodi4(uint64_t lhs, uint64_t rhs, int *overflow);
174ZIG_EXTERN_C uint128_t __uaddoti4(uint128_t lhs, uint128_t rhs, int *overflow);
175ZIG_EXTERN_C int32_t __subosi4(int32_t lhs, int32_t rhs, int *overflow);
176ZIG_EXTERN_C int64_t __subodi4(int64_t lhs, int64_t rhs, int *overflow);
177ZIG_EXTERN_C int128_t __suboti4(int128_t lhs, int128_t rhs, int *overflow);
178ZIG_EXTERN_C uint32_t __usubosi4(uint32_t lhs, uint32_t rhs, int *overflow);
179ZIG_EXTERN_C uint64_t __usubodi4(uint64_t lhs, uint64_t rhs, int *overflow);
180ZIG_EXTERN_C uint128_t __usuboti4(uint128_t lhs, uint128_t rhs, int *overflow);
181ZIG_EXTERN_C int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow);
182ZIG_EXTERN_C int128_t __muloti4(int128_t lhs, int128_t rhs, int *overflow);
183ZIG_EXTERN_C uint64_t __umulodi4(uint64_t lhs, uint64_t rhs, int *overflow);
184ZIG_EXTERN_C uint128_t __umuloti4(uint128_t lhs, uint128_t rhs, int *overflow);
185
170186
171187static inline uint8_t zig_addw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) {
172188 uint8_t thresh = max - rhs;
......@@ -396,6 +412,811 @@ static inline long long zig_subw_longlong(long long lhs, long long rhs, long lon
396412 return (long long)(((unsigned long long)lhs) - ((unsigned long long)rhs));
397413}
398414
415static inline bool zig_addo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) {
416#if defined(__GNUC__) && INT8_MAX == INT_MAX
417 if (min == INT8_MIN && max == INT8_MAX) {
418 return __builtin_sadd_overflow(lhs, rhs, res);
419 }
420#elif defined(__GNUC__) && INT8_MAX == LONG_MAX
421 if (min == INT8_MIN && max == INT8_MAX) {
422 return __builtin_saddl_overflow(lhs, rhs, res);
423 }
424#elif defined(__GNUC__) && INT8_MAX == LLONG_MAX
425 if (min == INT8_MIN && max == INT8_MAX) {
426 return __builtin_saddll_overflow(lhs, rhs, res);
427 }
428#endif
429 int16_t big_result = (int16_t)lhs + (int16_t)rhs;
430 if (big_result > max) {
431 *res = big_result - ((int16_t)max - (int16_t)min);
432 return true;
433 }
434 if (big_result < min) {
435 *res = big_result + ((int16_t)max - (int16_t)min);
436 return true;
437 }
438 *res = big_result;
439 return false;
440}
441
442static inline bool zig_addo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) {
443#if defined(__GNUC__) && INT16_MAX == INT_MAX
444 if (min == INT16_MIN && max == INT16_MAX) {
445 return __builtin_sadd_overflow(lhs, rhs, res);
446 }
447#elif defined(__GNUC__) && INT16_MAX == LONG_MAX
448 if (min == INT16_MIN && max == INT16_MAX) {
449 return __builtin_saddl_overflow(lhs, rhs, res);
450 }
451#elif defined(__GNUC__) && INT16_MAX == LLONG_MAX
452 if (min == INT16_MIN && max == INT16_MAX) {
453 return __builtin_saddll_overflow(lhs, rhs, res);
454 }
455#endif
456 int32_t big_result = (int32_t)lhs + (int32_t)rhs;
457 if (big_result > max) {
458 *res = big_result - ((int32_t)max - (int32_t)min);
459 return true;
460 }
461 if (big_result < min) {
462 *res = big_result + ((int32_t)max - (int32_t)min);
463 return true;
464 }
465 *res = big_result;
466 return false;
467}
468
469static inline bool zig_addo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) {
470#if defined(__GNUC__) && INT32_MAX == INT_MAX
471 if (min == INT32_MIN && max == INT32_MAX) {
472 return __builtin_sadd_overflow(lhs, rhs, res);
473 }
474#elif defined(__GNUC__) && INT32_MAX == LONG_MAX
475 if (min == INT32_MIN && max == INT32_MAX) {
476 return __builtin_saddl_overflow(lhs, rhs, res);
477 }
478#elif defined(__GNUC__) && INT32_MAX == LLONG_MAX
479 if (min == INT32_MIN && max == INT32_MAX) {
480 return __builtin_saddll_overflow(lhs, rhs, res);
481 }
482#endif
483 int64_t big_result = (int64_t)lhs + (int64_t)rhs;
484 if (big_result > max) {
485 *res = big_result - ((int64_t)max - (int64_t)min);
486 return true;
487 }
488 if (big_result < min) {
489 *res = big_result + ((int64_t)max - (int64_t)min);
490 return true;
491 }
492 *res = big_result;
493 return false;
494}
495
496static inline bool zig_addo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) {
497 bool overflow;
498#if defined(__GNUC__) && INT64_MAX == INT_MAX
499 overflow = __builtin_sadd_overflow(lhs, rhs, res);
500#elif defined(__GNUC__) && INT64_MAX == LONG_MAX
501 overflow = __builtin_saddl_overflow(lhs, rhs, res);
502#elif defined(__GNUC__) && INT64_MAX == LLONG_MAX
503 overflow = __builtin_saddll_overflow(lhs, rhs, res);
504#else
505 int int_overflow;
506 *res = __addodi4(lhs, rhs, &int_overflow);
507 overflow = int_overflow != 0;
508#endif
509 if (!overflow) {
510 if (*res > max) {
511 // TODO adjust the result to be the truncated bits
512 return true;
513 } else if (*res < min) {
514 // TODO adjust the result to be the truncated bits
515 return true;
516 }
517 }
518 return overflow;
519}
520
521static inline bool zig_addo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) {
522 bool overflow;
523#if defined(__GNUC__) && INT128_MAX == INT_MAX
524 overflow = __builtin_sadd_overflow(lhs, rhs, res);
525#elif defined(__GNUC__) && INT128_MAX == LONG_MAX
526 overflow = __builtin_saddl_overflow(lhs, rhs, res);
527#elif defined(__GNUC__) && INT128_MAX == LLONG_MAX
528 overflow = __builtin_saddll_overflow(lhs, rhs, res);
529#else
530 int int_overflow;
531 *res = __addoti4(lhs, rhs, &int_overflow);
532 overflow = int_overflow != 0;
533#endif
534 if (!overflow) {
535 if (*res > max) {
536 // TODO adjust the result to be the truncated bits
537 return true;
538 } else if (*res < min) {
539 // TODO adjust the result to be the truncated bits
540 return true;
541 }
542 }
543 return overflow;
544}
545
546static inline bool zig_addo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) {
547#if defined(__GNUC__) && UINT8_MAX == UINT_MAX
548 if (max == UINT8_MAX) {
549 return __builtin_uadd_overflow(lhs, rhs, res);
550 }
551#elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX
552 if (max == UINT8_MAX) {
553 return __builtin_uaddl_overflow(lhs, rhs, res);
554 }
555#elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX
556 if (max == UINT8_MAX) {
557 return __builtin_uaddll_overflow(lhs, rhs, res);
558 }
559#endif
560 uint16_t big_result = (uint16_t)lhs + (uint16_t)rhs;
561 if (big_result > max) {
562 *res = big_result - max - 1;
563 return true;
564 }
565 *res = big_result;
566 return false;
567}
568
569static inline uint16_t zig_addo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) {
570#if defined(__GNUC__) && UINT16_MAX == UINT_MAX
571 if (max == UINT16_MAX) {
572 return __builtin_uadd_overflow(lhs, rhs, res);
573 }
574#elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX
575 if (max == UINT16_MAX) {
576 return __builtin_uaddl_overflow(lhs, rhs, res);
577 }
578#elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX
579 if (max == UINT16_MAX) {
580 return __builtin_uaddll_overflow(lhs, rhs, res);
581 }
582#endif
583 uint32_t big_result = (uint32_t)lhs + (uint32_t)rhs;
584 if (big_result > max) {
585 *res = big_result - max - 1;
586 return true;
587 }
588 *res = big_result;
589 return false;
590}
591
592static inline uint32_t zig_addo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) {
593#if defined(__GNUC__) && UINT32_MAX == UINT_MAX
594 if (max == UINT32_MAX) {
595 return __builtin_uadd_overflow(lhs, rhs, res);
596 }
597#elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX
598 if (max == UINT32_MAX) {
599 return __builtin_uaddl_overflow(lhs, rhs, res);
600 }
601#elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX
602 if (max == UINT32_MAX) {
603 return __builtin_uaddll_overflow(lhs, rhs, res);
604 }
605#endif
606 uint64_t big_result = (uint64_t)lhs + (uint64_t)rhs;
607 if (big_result > max) {
608 *res = big_result - max - 1;
609 return true;
610 }
611 *res = big_result;
612 return false;
613}
614
615static inline uint64_t zig_addo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) {
616 bool overflow;
617#if defined(__GNUC__) && UINT64_MAX == UINT_MAX
618 overflow = __builtin_uadd_overflow(lhs, rhs, res);
619#elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX
620 overflow = __builtin_uaddl_overflow(lhs, rhs, res);
621#elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX
622 overflow = __builtin_uaddll_overflow(lhs, rhs, res);
623#else
624 int int_overflow;
625 *res = __uaddodi4(lhs, rhs, &int_overflow);
626 overflow = int_overflow != 0;
627#endif
628 if (*res > max && !overflow) {
629 *res -= max - 1;
630 return true;
631 }
632 return overflow;
633}
634
635static inline uint128_t zig_addo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) {
636 bool overflow;
637 *res = __uaddoti4(lhs, rhs, &overflow);
638 if (*res > max && !overflow) {
639 *res -= max - 1;
640 return true;
641 }
642 return overflow;
643}
644
645static inline bool zig_subo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) {
646#if defined(__GNUC__) && INT8_MAX == INT_MAX
647 if (min == INT8_MIN && max == INT8_MAX) {
648 return __builtin_ssub_overflow(lhs, rhs, res);
649 }
650#elif defined(__GNUC__) && INT8_MAX == LONG_MAX
651 if (min == INT8_MIN && max == INT8_MAX) {
652 return __builtin_ssubl_overflow(lhs, rhs, res);
653 }
654#elif defined(__GNUC__) && INT8_MAX == LLONG_MAX
655 if (min == INT8_MIN && max == INT8_MAX) {
656 return __builtin_ssubll_overflow(lhs, rhs, res);
657 }
658#endif
659 int16_t big_result = (int16_t)lhs - (int16_t)rhs;
660 if (big_result > max) {
661 *res = big_result - ((int16_t)max - (int16_t)min);
662 return true;
663 }
664 if (big_result < min) {
665 *res = big_result + ((int16_t)max - (int16_t)min);
666 return true;
667 }
668 *res = big_result;
669 return false;
670}
671
672static inline bool zig_subo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) {
673#if defined(__GNUC__) && INT16_MAX == INT_MAX
674 if (min == INT16_MIN && max == INT16_MAX) {
675 return __builtin_ssub_overflow(lhs, rhs, res);
676 }
677#elif defined(__GNUC__) && INT16_MAX == LONG_MAX
678 if (min == INT16_MIN && max == INT16_MAX) {
679 return __builtin_ssubl_overflow(lhs, rhs, res);
680 }
681#elif defined(__GNUC__) && INT16_MAX == LLONG_MAX
682 if (min == INT16_MIN && max == INT16_MAX) {
683 return __builtin_ssubll_overflow(lhs, rhs, res);
684 }
685#endif
686 int32_t big_result = (int32_t)lhs - (int32_t)rhs;
687 if (big_result > max) {
688 *res = big_result - ((int32_t)max - (int32_t)min);
689 return true;
690 }
691 if (big_result < min) {
692 *res = big_result + ((int32_t)max - (int32_t)min);
693 return true;
694 }
695 *res = big_result;
696 return false;
697}
698
699static inline bool zig_subo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) {
700#if defined(__GNUC__) && INT32_MAX == INT_MAX
701 if (min == INT32_MIN && max == INT32_MAX) {
702 return __builtin_ssub_overflow(lhs, rhs, res);
703 }
704#elif defined(__GNUC__) && INT32_MAX == LONG_MAX
705 if (min == INT32_MIN && max == INT32_MAX) {
706 return __builtin_ssubl_overflow(lhs, rhs, res);
707 }
708#elif defined(__GNUC__) && INT32_MAX == LLONG_MAX
709 if (min == INT32_MIN && max == INT32_MAX) {
710 return __builtin_ssubll_overflow(lhs, rhs, res);
711 }
712#endif
713 int64_t big_result = (int64_t)lhs - (int64_t)rhs;
714 if (big_result > max) {
715 *res = big_result - ((int64_t)max - (int64_t)min);
716 return true;
717 }
718 if (big_result < min) {
719 *res = big_result + ((int64_t)max - (int64_t)min);
720 return true;
721 }
722 *res = big_result;
723 return false;
724}
725
726static inline bool zig_subo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) {
727 bool overflow;
728#if defined(__GNUC__) && INT64_MAX == INT_MAX
729 overflow = __builtin_ssub_overflow(lhs, rhs, res);
730#elif defined(__GNUC__) && INT64_MAX == LONG_MAX
731 overflow = __builtin_ssubl_overflow(lhs, rhs, res);
732#elif defined(__GNUC__) && INT64_MAX == LLONG_MAX
733 overflow = __builtin_ssubll_overflow(lhs, rhs, res);
734#else
735 int int_overflow;
736 *res = __subodi4(lhs, rhs, &int_overflow);
737 overflow = int_overflow != 0;
738#endif
739 if (!overflow) {
740 if (*res > max) {
741 // TODO adjust the result to be the truncated bits
742 return true;
743 } else if (*res < min) {
744 // TODO adjust the result to be the truncated bits
745 return true;
746 }
747 }
748 return overflow;
749}
750
751static inline bool zig_subo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) {
752 bool overflow;
753#if defined(__GNUC__) && INT128_MAX == INT_MAX
754 overflow = __builtin_ssub_overflow(lhs, rhs, res);
755#elif defined(__GNUC__) && INT128_MAX == LONG_MAX
756 overflow = __builtin_ssubl_overflow(lhs, rhs, res);
757#elif defined(__GNUC__) && INT128_MAX == LLONG_MAX
758 overflow = __builtin_ssubll_overflow(lhs, rhs, res);
759#else
760 int int_overflow;
761 *res = __suboti4(lhs, rhs, &int_overflow);
762 overflow = int_overflow != 0;
763#endif
764 if (!overflow) {
765 if (*res > max) {
766 // TODO adjust the result to be the truncated bits
767 return true;
768 } else if (*res < min) {
769 // TODO adjust the result to be the truncated bits
770 return true;
771 }
772 }
773 return overflow;
774}
775
776static inline bool zig_subo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) {
777#if defined(__GNUC__) && UINT8_MAX == UINT_MAX
778 return __builtin_usub_overflow(lhs, rhs, res);
779#elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX
780 return __builtin_usubl_overflow(lhs, rhs, res);
781#elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX
782 return __builtin_usubll_overflow(lhs, rhs, res);
783#endif
784 if (rhs > lhs) {
785 *res = max - (rhs - lhs - 1);
786 return true;
787 }
788 *res = lhs - rhs;
789 return false;
790}
791
792static inline uint16_t zig_subo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) {
793#if defined(__GNUC__) && UINT16_MAX == UINT_MAX
794 return __builtin_usub_overflow(lhs, rhs, res);
795#elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX
796 return __builtin_usubl_overflow(lhs, rhs, res);
797#elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX
798 return __builtin_usubll_overflow(lhs, rhs, res);
799#endif
800 if (rhs > lhs) {
801 *res = max - (rhs - lhs - 1);
802 return true;
803 }
804 *res = lhs - rhs;
805 return false;
806}
807
808static inline uint32_t zig_subo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) {
809 if (max == UINT32_MAX) {
810#if defined(__GNUC__) && UINT32_MAX == UINT_MAX
811 return __builtin_usub_overflow(lhs, rhs, res);
812#elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX
813 return __builtin_usubl_overflow(lhs, rhs, res);
814#elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX
815 return __builtin_usubll_overflow(lhs, rhs, res);
816#endif
817 int int_overflow;
818 *res = __usubosi4(lhs, rhs, &int_overflow);
819 return int_overflow != 0;
820 } else {
821 if (rhs > lhs) {
822 *res = max - (rhs - lhs - 1);
823 return true;
824 }
825 *res = lhs - rhs;
826 return false;
827 }
828}
829
830static inline uint64_t zig_subo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) {
831 if (max == UINT64_MAX) {
832#if defined(__GNUC__) && UINT64_MAX == UINT_MAX
833 return __builtin_usub_overflow(lhs, rhs, res);
834#elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX
835 return __builtin_usubl_overflow(lhs, rhs, res);
836#elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX
837 return __builtin_usubll_overflow(lhs, rhs, res);
838#else
839 int int_overflow;
840 *res = __usubodi4(lhs, rhs, &int_overflow);
841 return int_overflow != 0;
842#endif
843 } else {
844 if (rhs > lhs) {
845 *res = max - (rhs - lhs - 1);
846 return true;
847 }
848 *res = lhs - rhs;
849 return false;
850 }
851}
852
853static inline uint128_t zig_subo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) {
854 if (max == UINT128_MAX) {
855 int int_overflow;
856 *res = __usuboti4(lhs, rhs, &int_overflow);
857 return int_overflow != 0;
858 } else {
859 if (rhs > lhs) {
860 *res = max - (rhs - lhs - 1);
861 return true;
862 }
863 *res = lhs - rhs;
864 return false;
865 }
866}
867
868static inline bool zig_mulo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) {
869#if defined(__GNUC__) && INT8_MAX == INT_MAX
870 if (min == INT8_MIN && max == INT8_MAX) {
871 return __builtin_smul_overflow(lhs, rhs, res);
872 }
873#elif defined(__GNUC__) && INT8_MAX == LONG_MAX
874 if (min == INT8_MIN && max == INT8_MAX) {
875 return __builtin_smull_overflow(lhs, rhs, res);
876 }
877#elif defined(__GNUC__) && INT8_MAX == LLONG_MAX
878 if (min == INT8_MIN && max == INT8_MAX) {
879 return __builtin_smulll_overflow(lhs, rhs, res);
880 }
881#endif
882 int16_t big_result = (int16_t)lhs * (int16_t)rhs;
883 if (big_result > max) {
884 *res = big_result - ((int16_t)max - (int16_t)min);
885 return true;
886 }
887 if (big_result < min) {
888 *res = big_result + ((int16_t)max - (int16_t)min);
889 return true;
890 }
891 *res = big_result;
892 return false;
893}
894
895static inline bool zig_mulo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) {
896#if defined(__GNUC__) && INT16_MAX == INT_MAX
897 if (min == INT16_MIN && max == INT16_MAX) {
898 return __builtin_smul_overflow(lhs, rhs, res);
899 }
900#elif defined(__GNUC__) && INT16_MAX == LONG_MAX
901 if (min == INT16_MIN && max == INT16_MAX) {
902 return __builtin_smull_overflow(lhs, rhs, res);
903 }
904#elif defined(__GNUC__) && INT16_MAX == LLONG_MAX
905 if (min == INT16_MIN && max == INT16_MAX) {
906 return __builtin_smulll_overflow(lhs, rhs, res);
907 }
908#endif
909 int32_t big_result = (int32_t)lhs * (int32_t)rhs;
910 if (big_result > max) {
911 *res = big_result - ((int32_t)max - (int32_t)min);
912 return true;
913 }
914 if (big_result < min) {
915 *res = big_result + ((int32_t)max - (int32_t)min);
916 return true;
917 }
918 *res = big_result;
919 return false;
920}
921
922static inline bool zig_mulo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) {
923#if defined(__GNUC__) && INT32_MAX == INT_MAX
924 if (min == INT32_MIN && max == INT32_MAX) {
925 return __builtin_smul_overflow(lhs, rhs, res);
926 }
927#elif defined(__GNUC__) && INT32_MAX == LONG_MAX
928 if (min == INT32_MIN && max == INT32_MAX) {
929 return __builtin_smull_overflow(lhs, rhs, res);
930 }
931#elif defined(__GNUC__) && INT32_MAX == LLONG_MAX
932 if (min == INT32_MIN && max == INT32_MAX) {
933 return __builtin_smulll_overflow(lhs, rhs, res);
934 }
935#endif
936 int64_t big_result = (int64_t)lhs * (int64_t)rhs;
937 if (big_result > max) {
938 *res = big_result - ((int64_t)max - (int64_t)min);
939 return true;
940 }
941 if (big_result < min) {
942 *res = big_result + ((int64_t)max - (int64_t)min);
943 return true;
944 }
945 *res = big_result;
946 return false;
947}
948
949static inline bool zig_mulo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) {
950 bool overflow;
951#if defined(__GNUC__) && INT64_MAX == INT_MAX
952 overflow = __builtin_smul_overflow(lhs, rhs, res);
953#elif defined(__GNUC__) && INT64_MAX == LONG_MAX
954 overflow = __builtin_smull_overflow(lhs, rhs, res);
955#elif defined(__GNUC__) && INT64_MAX == LLONG_MAX
956 overflow = __builtin_smulll_overflow(lhs, rhs, res);
957#else
958 int int_overflow;
959 *res = __mulodi4(lhs, rhs, &int_overflow);
960 overflow = int_overflow != 0;
961#endif
962 if (!overflow) {
963 if (*res > max) {
964 // TODO adjust the result to be the truncated bits
965 return true;
966 } else if (*res < min) {
967 // TODO adjust the result to be the truncated bits
968 return true;
969 }
970 }
971 return overflow;
972}
973
974static inline bool zig_mulo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) {
975 bool overflow;
976#if defined(__GNUC__) && INT128_MAX == INT_MAX
977 overflow = __builtin_smul_overflow(lhs, rhs, res);
978#elif defined(__GNUC__) && INT128_MAX == LONG_MAX
979 overflow = __builtin_smull_overflow(lhs, rhs, res);
980#elif defined(__GNUC__) && INT128_MAX == LLONG_MAX
981 overflow = __builtin_smulll_overflow(lhs, rhs, res);
982#else
983 int int_overflow;
984 *res = __muloti4(lhs, rhs, &int_overflow);
985 overflow = int_overflow != 0;
986#endif
987 if (!overflow) {
988 if (*res > max) {
989 // TODO adjust the result to be the truncated bits
990 return true;
991 } else if (*res < min) {
992 // TODO adjust the result to be the truncated bits
993 return true;
994 }
995 }
996 return overflow;
997}
998
999static inline bool zig_mulo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) {
1000#if defined(__GNUC__) && UINT8_MAX == UINT_MAX
1001 if (max == UINT8_MAX) {
1002 return __builtin_umul_overflow(lhs, rhs, res);
1003 }
1004#elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX
1005 if (max == UINT8_MAX) {
1006 return __builtin_umull_overflow(lhs, rhs, res);
1007 }
1008#elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX
1009 if (max == UINT8_MAX) {
1010 return __builtin_umulll_overflow(lhs, rhs, res);
1011 }
1012#endif
1013 uint16_t big_result = (uint16_t)lhs * (uint16_t)rhs;
1014 if (big_result > max) {
1015 *res = big_result - max - 1;
1016 return true;
1017 }
1018 *res = big_result;
1019 return false;
1020}
1021
1022static inline uint16_t zig_mulo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) {
1023#if defined(__GNUC__) && UINT16_MAX == UINT_MAX
1024 if (max == UINT16_MAX) {
1025 return __builtin_umul_overflow(lhs, rhs, res);
1026 }
1027#elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX
1028 if (max == UINT16_MAX) {
1029 return __builtin_umull_overflow(lhs, rhs, res);
1030 }
1031#elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX
1032 if (max == UINT16_MAX) {
1033 return __builtin_umulll_overflow(lhs, rhs, res);
1034 }
1035#endif
1036 uint32_t big_result = (uint32_t)lhs * (uint32_t)rhs;
1037 if (big_result > max) {
1038 *res = big_result - max - 1;
1039 return true;
1040 }
1041 *res = big_result;
1042 return false;
1043}
1044
1045static inline uint32_t zig_mulo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) {
1046#if defined(__GNUC__) && UINT32_MAX == UINT_MAX
1047 if (max == UINT32_MAX) {
1048 return __builtin_umul_overflow(lhs, rhs, res);
1049 }
1050#elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX
1051 if (max == UINT32_MAX) {
1052 return __builtin_umull_overflow(lhs, rhs, res);
1053 }
1054#elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX
1055 if (max == UINT32_MAX) {
1056 return __builtin_umulll_overflow(lhs, rhs, res);
1057 }
1058#endif
1059 uint64_t big_result = (uint64_t)lhs * (uint64_t)rhs;
1060 if (big_result > max) {
1061 *res = big_result - max - 1;
1062 return true;
1063 }
1064 *res = big_result;
1065 return false;
1066}
1067
1068static inline uint64_t zig_mulo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) {
1069 bool overflow;
1070#if defined(__GNUC__) && UINT64_MAX == UINT_MAX
1071 overflow = __builtin_umul_overflow(lhs, rhs, res);
1072#elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX
1073 overflow = __builtin_umull_overflow(lhs, rhs, res);
1074#elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX
1075 overflow = __builtin_umulll_overflow(lhs, rhs, res);
1076#else
1077 int int_overflow;
1078 *res = __umulodi4(lhs, rhs, &int_overflow);
1079 overflow = int_overflow != 0;
1080#endif
1081 if (*res > max && !overflow) {
1082 *res -= max - 1;
1083 return true;
1084 }
1085 return overflow;
1086}
1087
1088static inline uint128_t zig_mulo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) {
1089 int overflow;
1090 *res = __umuloti4(lhs, rhs, &overflow);
1091 if (*res > max && overflow == 0) {
1092 *res -= max - 1;
1093 return true;
1094 }
1095 return overflow != 0;
1096}
1097
1098static inline bool zig_shlo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) {
1099 int16_t big_result = (int16_t)lhs << (int16_t)rhs;
1100 if (big_result > max) {
1101 *res = big_result - ((int16_t)max - (int16_t)min);
1102 return true;
1103 }
1104 if (big_result < min) {
1105 *res = big_result + ((int16_t)max - (int16_t)min);
1106 return true;
1107 }
1108 *res = big_result;
1109 return false;
1110}
1111
1112static inline bool zig_shlo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) {
1113 int32_t big_result = (int32_t)lhs << (int32_t)rhs;
1114 if (big_result > max) {
1115 *res = big_result - ((int32_t)max - (int32_t)min);
1116 return true;
1117 }
1118 if (big_result < min) {
1119 *res = big_result + ((int32_t)max - (int32_t)min);
1120 return true;
1121 }
1122 *res = big_result;
1123 return false;
1124}
1125
1126static inline bool zig_shlo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) {
1127 int64_t big_result = (int64_t)lhs << (int64_t)rhs;
1128 if (big_result > max) {
1129 *res = big_result - ((int64_t)max - (int64_t)min);
1130 return true;
1131 }
1132 if (big_result < min) {
1133 *res = big_result + ((int64_t)max - (int64_t)min);
1134 return true;
1135 }
1136 *res = big_result;
1137 return false;
1138}
1139
1140static inline bool zig_shlo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) {
1141 int overflow;
1142 *res = __shlodi4(lhs, rhs, &overflow);
1143 if (overflow == 0) {
1144 if (*res > max) {
1145 // TODO adjust the result to be the truncated bits
1146 return true;
1147 } else if (*res < min) {
1148 // TODO adjust the result to be the truncated bits
1149 return true;
1150 }
1151 }
1152 return overflow != 0;
1153}
1154
1155static inline bool zig_shlo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) {
1156 int overflow;
1157 *res = __shloti4(lhs, rhs, &overflow);
1158 if (overflow == 0) {
1159 if (*res > max) {
1160 // TODO adjust the result to be the truncated bits
1161 return true;
1162 } else if (*res < min) {
1163 // TODO adjust the result to be the truncated bits
1164 return true;
1165 }
1166 }
1167 return overflow != 0;
1168}
1169
1170static inline bool zig_shlo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) {
1171 uint16_t big_result = (uint16_t)lhs << (uint16_t)rhs;
1172 if (big_result > max) {
1173 *res = big_result - max - 1;
1174 return true;
1175 }
1176 *res = big_result;
1177 return false;
1178}
1179
1180static inline uint16_t zig_shlo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) {
1181 uint32_t big_result = (uint32_t)lhs << (uint32_t)rhs;
1182 if (big_result > max) {
1183 *res = big_result - max - 1;
1184 return true;
1185 }
1186 *res = big_result;
1187 return false;
1188}
1189
1190static inline uint32_t zig_shlo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) {
1191 uint64_t big_result = (uint64_t)lhs << (uint64_t)rhs;
1192 if (big_result > max) {
1193 *res = big_result - max - 1;
1194 return true;
1195 }
1196 *res = big_result;
1197 return false;
1198}
1199
1200static inline uint64_t zig_shlo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) {
1201 int overflow;
1202 *res = __ushlodi4(lhs, rhs, &overflow);
1203 if (*res > max && overflow == 0) {
1204 *res -= max - 1;
1205 return true;
1206 }
1207 return overflow != 0;
1208}
1209
1210static inline uint128_t zig_shlo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) {
1211 int overflow;
1212 *res = __ushloti4(lhs, rhs, &overflow);
1213 if (*res > max && overflow == 0) {
1214 *res -= max - 1;
1215 return true;
1216 }
1217 return overflow != 0;
1218}
1219
3991220static inline float zig_bitcast_f32_u32(uint32_t arg) {
4001221 float dest;
4011222 memcpy(&dest, &arg, sizeof dest);