diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index e60eee1771..b69e608c4d 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -88,6 +88,7 @@ comptime { const num = @import("num.zig"); const INTEGERS = [_]type{ i8, i16, i32, i64, i128, u8, u16, u32, u64, u128 }; +const WIDEINTS = [_]type{ i16, i32, i64, i128, i256, u16, u32, u64, u128, u256 }; const FLOATS = [_]type{ f32, f64 }; const NUMBERS = INTEGERS ++ FLOATS; @@ -95,9 +96,16 @@ comptime { exportNumFn(num.bytesToU16C, "bytes_to_u16"); exportNumFn(num.bytesToU32C, "bytes_to_u32"); - inline for (INTEGERS) |T| { + inline for (INTEGERS) |T, i| { num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow_int."); num.exportDivCeil(T, ROC_BUILTINS ++ "." ++ NUM ++ ".div_ceil."); + + num.exportRoundF32(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f32."); + num.exportRoundF64(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f64."); + + num.exportAddWithOverflow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".add_with_overflow."); + const Wider = WIDEINTS[i]; + num.exportAddSaturatedInt(T, Wider, ROC_BUILTINS ++ "." ++ NUM ++ ".add_saturated."); } inline for (INTEGERS) |FROM| { @@ -106,11 +114,6 @@ comptime { num.exportToIntCheckingMax(FROM, TO, ROC_BUILTINS ++ "." ++ NUM ++ ".int_to_" ++ @typeName(TO) ++ "_checking_max."); num.exportToIntCheckingMaxAndMin(FROM, TO, ROC_BUILTINS ++ "." ++ NUM ++ ".int_to_" ++ @typeName(TO) ++ "_checking_max_and_min."); } - - num.exportRoundF32(FROM, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f32."); - num.exportRoundF64(FROM, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f64."); - - num.exportAddWithOverflow(FROM, ROC_BUILTINS ++ "." ++ NUM ++ ".add_with_overflow."); } inline for (FLOATS) |T| { diff --git a/compiler/builtins/bitcode/src/num.zig b/compiler/builtins/bitcode/src/num.zig index e13319ea1d..aff872a588 100644 --- a/compiler/builtins/bitcode/src/num.zig +++ b/compiler/builtins/bitcode/src/num.zig @@ -207,7 +207,7 @@ fn addWithOverflow(comptime T: type, self: T, other: T) WithOverflow(T) { const answer = self + other; const overflowed = !std.math.isFinite(answer); return .{ .value = answer, .has_overflowed = overflowed }; - } + }, } } @@ -219,3 +219,25 @@ pub fn exportAddWithOverflow(comptime T: type, comptime name: []const u8) void { }.func; @export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong }); } + +pub fn exportAddSaturatedInt(comptime T: type, comptime Wider: type, comptime name: []const u8) void { + comptime var f = struct { + fn func(self: T, other: T) callconv(.C) T { + const self_w = @intCast(Wider, self); + const other_w = @intCast(Wider, other); + const answer = self_w + other_w; + + const max = @intCast(Wider, std.math.maxInt(T)); + const min = @intCast(Wider, std.math.minInt(T)); + + if (answer > max) { + return max; + } else if (answer < min) { + return min; + } else { + return @intCast(T, answer); + } + } + }.func; + @export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong }); +}