authorgravatar for daniele.cocca@gmail.comDaniele Cocca <daniele.cocca@gmail.com> 2022-03-11 11:48:11+00:00
committergravatar for daniele.cocca@gmail.comDaniele Cocca <daniele.cocca@gmail.com> 2022-03-11 23:12:15+00:00
log226fcd7c709ec664c5d883042cf7beb3026f66cb
tree200bd4f31e1328d7a94a106a437d3d0ebd0b9569
parent6dcfbfbfb2103082603f34fd5bd7c26616eda8c1

CBE: implement clz, ctz for ints <= 128 bits


3 files changed, 54 insertions(+), 4 deletions(-)

src/codegen/c.zig+22-2
......@@ -1708,8 +1708,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17081708 .memcpy => try airMemcpy(f, inst),
17091709 .set_union_tag => try airSetUnionTag(f, inst),
17101710 .get_union_tag => try airGetUnionTag(f, inst),
1711 .clz => try airBuiltinCall(f, inst, "clz"),
1712 .ctz => try airBuiltinCall(f, inst, "ctz"),
1711 .clz => try airCountZeroes(f, inst, "clz"),
1712 .ctz => try airCountZeroes(f, inst, "ctz"),
17131713 .popcount => try airBuiltinCall(f, inst, "popcount"),
17141714 .byte_swap => try airBuiltinCall(f, inst, "byte_swap"),
17151715 .bit_reverse => try airBuiltinCall(f, inst, "bit_reverse"),
......@@ -3349,6 +3349,26 @@ fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !C
33493349 return local;
33503350}
33513351
3352fn airCountZeroes(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
3353 if (f.liveness.isUnused(inst)) return CValue.none;
3354
3355 const inst_ty = f.air.typeOfIndex(inst);
3356 const local = try f.allocLocal(inst_ty, .Const);
3357 const operand = f.air.instructions.items(.data)[inst].ty_op.operand;
3358 const operand_ty = f.air.typeOf(operand);
3359 const target = f.object.dg.module.getTarget();
3360 const writer = f.object.writer();
3361
3362 const zig_bits = operand_ty.intInfo(target).bits;
3363 _ = toCIntBits(zig_bits) orelse
3364 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
3365
3366 try writer.print(" = zig_{s}(", .{fn_name});
3367 try f.writeCValue(writer, try f.resolveInst(operand));
3368 try writer.print(", {d});\n", .{zig_bits});
3369 return local;
3370}
3371
33523372fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
33533373 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
33543374 const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
src/link/C/zig.h+18
......@@ -500,3 +500,21 @@ zig_shl_sat_s(isize, intptr_t, ((sizeof(intptr_t)) * CHAR_BIT - 1))
500500zig_shl_sat_s(short, short, ((sizeof(short )) * CHAR_BIT - 1))
501501zig_shl_sat_s(int, int, ((sizeof(int )) * CHAR_BIT - 1))
502502zig_shl_sat_s(long, long, ((sizeof(long )) * CHAR_BIT - 1))
503
504#define zig_bitsizeof(T) (CHAR_BIT * sizeof(T))
505
506static inline int zig_clz(uint64_t value, uint8_t zig_type_bit_width) {
507 if (value == 0) return zig_type_bit_width;
508 if (zig_type_bit_width <= zig_bitsizeof(unsigned int))
509 return (__builtin_clz(value) - zig_bitsizeof(unsigned int) + zig_type_bit_width);
510 if (zig_type_bit_width <= zig_bitsizeof(unsigned long))
511 return (__builtin_clzl(value) - zig_bitsizeof(unsigned long) + zig_type_bit_width);
512 return (__builtin_clzll(value) - zig_bitsizeof(unsigned long long) + zig_type_bit_width);
513}
514
515static inline int zig_ctz(uint64_t value, uint8_t zig_type_bit_width) {
516 if (value == 0) return zig_type_bit_width;
517 if (zig_type_bit_width <= zig_bitsizeof(unsigned int)) return __builtin_ctz(value);
518 if (zig_type_bit_width <= zig_bitsizeof(unsigned long)) return __builtin_ctzl(value);
519 return __builtin_ctzll(value);
520}
test/behavior/math.zig+14-2
......@@ -65,7 +65,6 @@ test "@clz" {
6565 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6767 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
6968
7069 try testClz();
7170 comptime try testClz();
......@@ -76,6 +75,20 @@ fn testClz() !void {
7675 try expect(testOneClz(u8, 0b00001010) == 4);
7776 try expect(testOneClz(u8, 0b00011010) == 3);
7877 try expect(testOneClz(u8, 0b00000000) == 8);
78}
79
80test "@clz big ints" {
81 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
86
87 try testClzBigInts();
88 comptime try testClzBigInts();
89}
90
91fn testClzBigInts() !void {
7992 try expect(testOneClz(u128, 0xffffffffffffffff) == 64);
8093 try expect(testOneClz(u128, 0x10000000000000000) == 63);
8194}
......@@ -130,7 +143,6 @@ test "@ctz" {
130143 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
131144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
132145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
134146
135147 try testCtz();
136148 comptime try testCtz();