Skip to content

Commit 6a98bf3

Browse files
committed
compiler_rt implementations for __fixuns* functions
* add u128 and i128 integer types * add f128 floating point type * implement big integer multiplication (See #405)
1 parent cf46cd5 commit 6a98bf3

27 files changed

+588
-22
lines changed

CMakeLists.txt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,10 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}")
239239
install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}")
240240
install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
241241
install(FILES "${CMAKE_SOURCE_DIR}/std/endian.zig" DESTINATION "${ZIG_STD_DEST}")
242-
install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt")
243-
install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol")
244242
install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/enum3.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol")
243+
install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol")
245244
install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/lookup.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol")
245+
install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt")
246246
install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
247247
install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
248248
install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
@@ -303,15 +303,27 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST
303303
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}/os")
304304
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os")
305305
install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")
306-
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/index.zig" DESTINATION "${ZIG_STD_DEST}/os/windows")
307306
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/error.zig" DESTINATION "${ZIG_STD_DEST}/os/windows")
307+
install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/index.zig" DESTINATION "${ZIG_STD_DEST}/os/windows")
308308
install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
309309
install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
310310
install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")
311311
install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_file_template.zig" DESTINATION "${ZIG_STD_DEST}/special")
312312
install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
313313
install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_STD_DEST}/special")
314+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixuint.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
315+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunsdfdi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
316+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunsdfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
317+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunsdfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
318+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunssfdi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
319+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunssfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
320+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunssfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
321+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfdi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
322+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
323+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
314324
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/index.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
325+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
326+
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
315327
install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
316328
install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
317329

src/all_types.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1386,22 +1386,25 @@ struct CodeGen {
13861386

13871387
struct {
13881388
TypeTableEntry *entry_bool;
1389-
TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
1389+
TypeTableEntry *entry_int[2][5]; // [signed,unsigned][8,16,32,64,128]
13901390
TypeTableEntry *entry_c_int[CIntTypeCount];
13911391
TypeTableEntry *entry_c_longdouble;
13921392
TypeTableEntry *entry_c_void;
13931393
TypeTableEntry *entry_u8;
13941394
TypeTableEntry *entry_u16;
13951395
TypeTableEntry *entry_u32;
13961396
TypeTableEntry *entry_u64;
1397+
TypeTableEntry *entry_u128;
13971398
TypeTableEntry *entry_i8;
13981399
TypeTableEntry *entry_i16;
13991400
TypeTableEntry *entry_i32;
14001401
TypeTableEntry *entry_i64;
1402+
TypeTableEntry *entry_i128;
14011403
TypeTableEntry *entry_isize;
14021404
TypeTableEntry *entry_usize;
14031405
TypeTableEntry *entry_f32;
14041406
TypeTableEntry *entry_f64;
1407+
TypeTableEntry *entry_f128;
14051408
TypeTableEntry *entry_void;
14061409
TypeTableEntry *entry_unreachable;
14071410
TypeTableEntry *entry_type;

src/analyze.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,8 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b
30853085
index = 2;
30863086
} else if (size_in_bits == 64) {
30873087
index = 3;
3088+
} else if (size_in_bits == 128) {
3089+
index = 4;
30883090
} else {
30893091
return nullptr;
30903092
}

src/bigint.cpp

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,6 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
373373
bigint_normalize(dest);
374374
return;
375375
}
376-
// TODO this code path is untested
377376
size_t i = 1;
378377
uint64_t first_digit = dest->data.digit;
379378
dest->data.digits = allocate_nonzero<uint64_t>(max(op1->digit_count, op2->digit_count) + 1);
@@ -397,17 +396,14 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
397396
}
398397

399398
dest->data.digits[i] = x;
400-
x += 1;
399+
i += 1;
401400

402401
if (!found_digit) {
403-
break;
402+
dest->digit_count = i;
403+
bigint_normalize(dest);
404+
return;
404405
}
405406
}
406-
if (overflow > 0) {
407-
dest->data.digits[i] = overflow;
408-
}
409-
bigint_normalize(dest);
410-
return;
411407
}
412408
const BigInt *op_pos;
413409
const BigInt *op_neg;
@@ -500,12 +496,49 @@ static void mul_overflow(uint64_t x, uint64_t y, uint64_t *result, uint64_t *car
500496
*carry = 0;
501497
return;
502498
}
503-
zig_panic("TODO bigint_mul with big numbers");
504499

505-
//unsigned __int128 big_x = x;
506-
//unsigned __int128 big_y = y;
507-
//unsigned __int128 big_result = big_x * big_y;
508-
//*carry = big_result >> 64;
500+
unsigned __int128 big_x = x;
501+
unsigned __int128 big_y = y;
502+
unsigned __int128 big_result = big_x * big_y;
503+
*carry = big_result >> 64;
504+
}
505+
506+
static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar) {
507+
bigint_init_unsigned(dest, 0);
508+
509+
BigInt bi_64;
510+
bigint_init_unsigned(&bi_64, 64);
511+
512+
const uint64_t *op_digits = bigint_ptr(op);
513+
size_t i = op->digit_count - 1;
514+
515+
for (;;) {
516+
BigInt shifted;
517+
bigint_shl(&shifted, dest, &bi_64);
518+
519+
uint64_t result_scalar;
520+
uint64_t carry_scalar;
521+
mul_overflow(scalar, op_digits[i], &result_scalar, &carry_scalar);
522+
523+
BigInt result;
524+
bigint_init_unsigned(&result, result_scalar);
525+
526+
BigInt carry;
527+
bigint_init_unsigned(&carry, carry_scalar);
528+
529+
BigInt carry_shifted;
530+
bigint_shl(&carry_shifted, &carry, &bi_64);
531+
532+
BigInt tmp;
533+
bigint_add(&tmp, &shifted, &carry_shifted);
534+
535+
bigint_add(dest, &tmp, &result);
536+
537+
if (i == 0) {
538+
break;
539+
}
540+
i -= 1;
541+
}
509542
}
510543

511544
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) {
@@ -523,7 +556,30 @@ void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) {
523556
bigint_normalize(dest);
524557
return;
525558
}
526-
zig_panic("TODO bigint_mul with big numbers");
559+
560+
bigint_init_unsigned(dest, 0);
561+
562+
BigInt bi_64;
563+
bigint_init_unsigned(&bi_64, 64);
564+
565+
size_t i = op2->digit_count - 1;
566+
for (;;) {
567+
BigInt shifted;
568+
bigint_shl(&shifted, dest, &bi_64);
569+
570+
BigInt scalar_result;
571+
mul_scalar(&scalar_result, op1, op2_digits[i]);
572+
573+
bigint_add(dest, &scalar_result, &shifted);
574+
575+
if (i == 0) {
576+
break;
577+
}
578+
i -= 1;
579+
}
580+
581+
dest->is_negative = (op1->is_negative != op2->is_negative);
582+
bigint_normalize(dest);
527583
}
528584

529585
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {

src/codegen.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4208,6 +4208,7 @@ static const uint8_t int_sizes_in_bits[] = {
42084208
16,
42094209
32,
42104210
64,
4211+
128,
42114212
};
42124213

42134214
struct CIntTypeInfo {
@@ -4390,6 +4391,19 @@ static void define_builtin_types(CodeGen *g) {
43904391
g->builtin_types.entry_f64 = entry;
43914392
g->primitive_type_table.put(&entry->name, entry);
43924393
}
4394+
{
4395+
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
4396+
entry->type_ref = LLVMFP128Type();
4397+
buf_init_from_str(&entry->name, "f128");
4398+
entry->data.floating.bit_count = 128;
4399+
4400+
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
4401+
entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
4402+
debug_size_in_bits,
4403+
ZigLLVMEncoding_DW_ATE_float());
4404+
g->builtin_types.entry_f128 = entry;
4405+
g->primitive_type_table.put(&entry->name, entry);
4406+
}
43934407
{
43944408
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
43954409
entry->type_ref = LLVMX86FP80Type();
@@ -4435,10 +4449,12 @@ static void define_builtin_types(CodeGen *g) {
44354449
g->builtin_types.entry_u16 = get_int_type(g, false, 16);
44364450
g->builtin_types.entry_u32 = get_int_type(g, false, 32);
44374451
g->builtin_types.entry_u64 = get_int_type(g, false, 64);
4452+
g->builtin_types.entry_u128 = get_int_type(g, false, 128);
44384453
g->builtin_types.entry_i8 = get_int_type(g, true, 8);
44394454
g->builtin_types.entry_i16 = get_int_type(g, true, 16);
44404455
g->builtin_types.entry_i32 = get_int_type(g, true, 32);
44414456
g->builtin_types.entry_i64 = get_int_type(g, true, 64);
4457+
g->builtin_types.entry_i128 = get_int_type(g, true, 128);
44424458

44434459
{
44444460
g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");

std/special/compiler_rt/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
This compiler-rt library is ported from [LLVM](http://compiler-rt.llvm.org/).
2+
3+
It's needed because LLVM emits library calls to compiler-rt when hardware lacks
4+
functionality, for example, 64-bit integer multiplication on 32-bit x86.
5+
6+
This library is automatically built as-needed for the compilation target and
7+
then statically linked and therefore is a transparent dependency for the
8+
programmer.
9+
10+
Any bugs should be solved by trying to duplicate the bug upstream.
11+
* If the bug exists upstream, get it fixed with the LLVM team and then port
12+
the fix downstream to Zig.
13+
* If the bug only exists in Zig, something went wrong porting the code,
14+
and you can run the C code and Zig code side by side in a debugger
15+
to figure out what's happening differently.

std/special/compiler_rt/fixuint.zig

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) -> fixuint_t {
2+
@setDebugSafety(this, true); // TODO
3+
4+
const rep_t = switch (fp_t) {
5+
f32 => u32,
6+
f64 => u64,
7+
f128 => u128,
8+
else => unreachable,
9+
};
10+
const srep_t = @IntType(true, rep_t.bit_count);
11+
const significandBits = switch (fp_t) {
12+
f32 => 23,
13+
f64 => 52,
14+
f128 => 112,
15+
else => unreachable,
16+
};
17+
const typeWidth = rep_t.bit_count;
18+
const exponentBits = (typeWidth - significandBits - 1);
19+
const signBit = (rep_t(1) << (significandBits + exponentBits));
20+
const maxExponent = ((1 << exponentBits) - 1);
21+
const exponentBias = (maxExponent >> 1);
22+
23+
const implicitBit = (rep_t(1) << significandBits);
24+
const significandMask = (implicitBit - 1);
25+
26+
// Break a into sign, exponent, significand
27+
const aRep: rep_t = @bitCast(rep_t, a);
28+
const absMask = signBit - 1;
29+
const aAbs: rep_t = aRep & absMask;
30+
31+
const sign = if ((aRep & signBit) != 0) i32(-1) else i32(1);
32+
const exponent = i32(aAbs >> significandBits) - exponentBias;
33+
const significand: rep_t = (aAbs & significandMask) | implicitBit;
34+
35+
// If either the value or the exponent is negative, the result is zero.
36+
if (sign == -1 or exponent < 0)
37+
return 0;
38+
39+
// If the value is too large for the integer type, saturate.
40+
if (c_uint(exponent) >= fixuint_t.bit_count)
41+
return ~fixuint_t(0);
42+
43+
// If 0 <= exponent < significandBits, right shift to get the result.
44+
// Otherwise, shift left.
45+
if (exponent < significandBits) {
46+
return fixuint_t(significand >> rep_t(significandBits - exponent));
47+
} else {
48+
return fixuint_t(significand) << fixuint_t(exponent - significandBits);
49+
}
50+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const fixuint = @import("fixuint.zig").fixuint;
2+
3+
export fn __fixunsdfdi(a: f64) -> u64 {
4+
return fixuint(f64, u64, a);
5+
}
6+
7+
test "import fixunsdfdi" {
8+
_ = @import("fixunsdfdi_test.zig");
9+
}
10+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2+
const assert = @import("../../debug.zig").assert;
3+
4+
fn test__fixunsdfdi(a: f64, expected: u64) {
5+
const x = __fixunsdfdi(a);
6+
assert(x == expected);
7+
}
8+
9+
test "fixunsdfdi" {
10+
test__fixunsdfdi(0.0, 0);
11+
test__fixunsdfdi(0.5, 0);
12+
test__fixunsdfdi(0.99, 0);
13+
test__fixunsdfdi(1.0, 1);
14+
test__fixunsdfdi(1.5, 1);
15+
test__fixunsdfdi(1.99, 1);
16+
test__fixunsdfdi(2.0, 2);
17+
test__fixunsdfdi(2.01, 2);
18+
test__fixunsdfdi(-0.5, 0);
19+
test__fixunsdfdi(-0.99, 0);
20+
test__fixunsdfdi(-1.0, 0);
21+
test__fixunsdfdi(-1.5, 0);
22+
test__fixunsdfdi(-1.99, 0);
23+
test__fixunsdfdi(-2.0, 0);
24+
test__fixunsdfdi(-2.01, 0);
25+
26+
test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
27+
test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
28+
29+
test__fixunsdfdi(-0x1.FFFFFEp+62, 0);
30+
test__fixunsdfdi(-0x1.FFFFFCp+62, 0);
31+
32+
test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800);
33+
test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000);
34+
test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
35+
test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
36+
37+
test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0);
38+
test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0);
39+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const fixuint = @import("fixuint.zig").fixuint;
2+
3+
export fn __fixunsdfsi(a: f64) -> u32 {
4+
return fixuint(f64, u32, a);
5+
}
6+
7+
test "import fixunsdfsi" {
8+
_ = @import("fixunsdfsi_test.zig");
9+
}
10+

0 commit comments

Comments
 (0)