authorgravatar for auguste.rame@gmail.comAuguste Rame <auguste.rame@gmail.com> 2021-07-25 22:43:52-04:00
committergravatar for auguste.rame@gmail.comAuguste Rame <auguste.rame@gmail.com> 2021-07-25 22:43:52-04:00
logc619b85f67386cac63463f0f801b4c316cfb6e95
tree890b96bc7070fbcb5d2cbb5a2fe0e3685a560222
parentecca829bcbfdcb03bfcefa56f530b180d5c61653

ctz + clz


4 files changed, 148 insertions(+), 24 deletions(-)

src/stage1/all_types.hpp+2
......@@ -1907,9 +1907,11 @@ struct ZigLLVMFnKey {
19071907 union {
19081908 struct {
19091909 uint32_t bit_count;
1910 uint32_t vector_len; // 0 means not a vector
19101911 } ctz;
19111912 struct {
19121913 uint32_t bit_count;
1914 uint32_t vector_len; // 0 means not a vector
19131915 } clz;
19141916 struct {
19151917 uint32_t bit_count;
src/stage1/analyze.cpp+4-2
......@@ -7883,9 +7883,11 @@ bool type_id_eql(TypeId const *a, TypeId const *b) {
78837883uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) {
78847884 switch (x->id) {
78857885 case ZigLLVMFnIdCtz:
7886 return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934;
7886 return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934 +
7887 (uint32_t)(x->data.ctz.vector_len) * (((uint32_t)x->id << 5) + 1025);
78877888 case ZigLLVMFnIdClz:
7888 return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817;
7889 return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817 +
7890 (uint32_t)(x->data.clz.vector_len) * (((uint32_t)x->id << 5) + 1025);
78897891 case ZigLLVMFnIdPopCount:
78907892 return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 +
78917893 (uint32_t)(x->data.pop_count.vector_len) * (((uint32_t)x->id << 5) + 1025);
src/stage1/ir.cpp+108-8
......@@ -15945,54 +15945,154 @@ static Stage1AirInst *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira,
1594515945}
1594615946
1594715947static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) {
15948 Error err;
15949
1594815950 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);
1594915951 if (type_is_invalid(int_type))
1595015952 return ira->codegen->invalid_inst_gen;
1595115953
15952 Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type);
15954 Stage1AirInst *uncasted_op = instruction->op->child;
15955 if (type_is_invalid(uncasted_op->value->type))
15956 return ira->codegen->invalid_inst_gen;
15957
15958 uint32_t vector_len = UINT32_MAX; // means not a vector
15959 if (uncasted_op->value->type->id == ZigTypeIdArray) {
15960 bool can_be_vec_elem;
15961 if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type,
15962 &can_be_vec_elem)))
15963 {
15964 return ira->codegen->invalid_inst_gen;
15965 }
15966 if (can_be_vec_elem) {
15967 vector_len = uncasted_op->value->type->data.array.len;
15968 }
15969 } else if (uncasted_op->value->type->id == ZigTypeIdVector) {
15970 vector_len = uncasted_op->value->type->data.vector.len;
15971 }
15972
15973 bool is_vector = (vector_len != UINT32_MAX);
15974 ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type;
15975
15976 Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type);
1595315977 if (type_is_invalid(op->value->type))
1595415978 return ira->codegen->invalid_inst_gen;
1595515979
1595615980 if (int_type->data.integral.bit_count == 0)
1595715981 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0);
1595815982
15983 ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count);
15984
1595915985 if (instr_is_comptime(op)) {
1596015986 ZigValue *val = ir_resolve_const(ira, op, UndefOk);
1596115987 if (val == nullptr)
1596215988 return ira->codegen->invalid_inst_gen;
1596315989 if (val->special == ConstValSpecialUndef)
1596415990 return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int);
15965 size_t result_usize = bigint_ctz(&op->value->data.x_bigint, int_type->data.integral.bit_count);
15966 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize);
15991
15992 if (is_vector) {
15993 ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type);
15994 Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type);
15995 expand_undef_array(ira->codegen, val);
15996 result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(smallest_vec_type->data.vector.len);
15997 for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) {
15998 ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i];
15999 if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node,
16000 op_elem_val, UndefOk)))
16001 {
16002 return ira->codegen->invalid_inst_gen;
16003 }
16004 ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i];
16005 result_elem_val->type = smallest_type;
16006 result_elem_val->special = op_elem_val->special;
16007 if (op_elem_val->special == ConstValSpecialUndef)
16008 continue;
16009 size_t value = bigint_ctz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count);
16010 bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value);
16011 }
16012 return result;
16013 } else {
16014 size_t result_usize = bigint_ctz(&op->value->data.x_bigint, int_type->data.integral.bit_count);
16015 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize);
16016 }
1596716017 }
1596816018
15969 ZigType *return_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count);
16019 ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type;
1597016020 return ir_build_ctz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);
1597116021}
1597216022
1597316023static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) {
16024 Error err;
16025
1597416026 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);
1597516027 if (type_is_invalid(int_type))
1597616028 return ira->codegen->invalid_inst_gen;
1597716029
15978 Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type);
16030 Stage1AirInst *uncasted_op = instruction->op->child;
16031 if (type_is_invalid(uncasted_op->value->type))
16032 return ira->codegen->invalid_inst_gen;
16033
16034 uint32_t vector_len = UINT32_MAX; // means not a vector
16035 if (uncasted_op->value->type->id == ZigTypeIdArray) {
16036 bool can_be_vec_elem;
16037 if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type,
16038 &can_be_vec_elem)))
16039 {
16040 return ira->codegen->invalid_inst_gen;
16041 }
16042 if (can_be_vec_elem) {
16043 vector_len = uncasted_op->value->type->data.array.len;
16044 }
16045 } else if (uncasted_op->value->type->id == ZigTypeIdVector) {
16046 vector_len = uncasted_op->value->type->data.vector.len;
16047 }
16048
16049 bool is_vector = (vector_len != UINT32_MAX);
16050 ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type;
16051
16052 Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type);
1597916053 if (type_is_invalid(op->value->type))
1598016054 return ira->codegen->invalid_inst_gen;
1598116055
1598216056 if (int_type->data.integral.bit_count == 0)
1598316057 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0);
1598416058
16059 ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count);
16060
1598516061 if (instr_is_comptime(op)) {
1598616062 ZigValue *val = ir_resolve_const(ira, op, UndefOk);
1598716063 if (val == nullptr)
1598816064 return ira->codegen->invalid_inst_gen;
1598916065 if (val->special == ConstValSpecialUndef)
1599016066 return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int);
15991 size_t result_usize = bigint_clz(&op->value->data.x_bigint, int_type->data.integral.bit_count);
15992 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize);
16067
16068 if (is_vector) {
16069 ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type);
16070 Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type);
16071 expand_undef_array(ira->codegen, val);
16072 result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(smallest_vec_type->data.vector.len);
16073 for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) {
16074 ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i];
16075 if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node,
16076 op_elem_val, UndefOk)))
16077 {
16078 return ira->codegen->invalid_inst_gen;
16079 }
16080 ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i];
16081 result_elem_val->type = smallest_type;
16082 result_elem_val->special = op_elem_val->special;
16083 if (op_elem_val->special == ConstValSpecialUndef)
16084 continue;
16085 size_t value = bigint_clz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count);
16086 bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value);
16087 }
16088 return result;
16089 } else {
16090 size_t result_usize = bigint_clz(&op->value->data.x_bigint, int_type->data.integral.bit_count);
16091 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize);
16092 }
1599316093 }
1599416094
15995 ZigType *return_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count);
16095 ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type;
1599616096 return ir_build_clz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);
1599716097}
1599816098
test/behavior/math.zig+34-14
......@@ -123,16 +123,27 @@ test "@clz" {
123123}
124124
125125fn testClz() !void {
126 try expect(clz(u8, 0b10001010) == 0);
127 try expect(clz(u8, 0b00001010) == 4);
128 try expect(clz(u8, 0b00011010) == 3);
129 try expect(clz(u8, 0b00000000) == 8);
130 try expect(clz(u128, 0xffffffffffffffff) == 64);
131 try expect(clz(u128, 0x10000000000000000) == 63);
126 try expect(@clz(u8, 0b10001010) == 0);
127 try expect(@clz(u8, 0b00001010) == 4);
128 try expect(@clz(u8, 0b00011010) == 3);
129 try expect(@clz(u8, 0b00000000) == 8);
130 try expect(@clz(u128, 0xffffffffffffffff) == 64);
131 try expect(@clz(u128, 0x10000000000000000) == 63);
132132}
133133
134fn clz(comptime T: type, x: T) usize {
135 return @clz(T, x);
134test "@clz vectors" {
135 try testClzVectors();
136 comptime try testClzVectors();
137}
138
139fn testClzVectors() !void {
140 @setEvalBranchQuota(10_000);
141 try expectEqual(@clz(u8, @splat(64, @as(u8, 0b10001010))), @splat(64, @as(u4, 0)));
142 try expectEqual(@clz(u8, @splat(64, @as(u8, 0b00001010))), @splat(64, @as(u4, 4)));
143 try expectEqual(@clz(u8, @splat(64, @as(u8, 0b00011010))), @splat(64, @as(u4, 3)));
144 try expectEqual(@clz(u8, @splat(64, @as(u8, 0b00000000))), @splat(64, @as(u4, 8)));
145 try expectEqual(@clz(u128, @splat(64, @as(u128, 0xffffffffffffffff))), @splat(64, @as(u8, 64)));
146 try expectEqual(@clz(u128, @splat(64, @as(u128, 0x10000000000000000))), @splat(64, @as(u8, 63)));
136147}
137148
138149test "@ctz" {
......@@ -141,14 +152,23 @@ test "@ctz" {
141152}
142153
143154fn testCtz() !void {
144 try expect(ctz(u8, 0b10100000) == 5);
145 try expect(ctz(u8, 0b10001010) == 1);
146 try expect(ctz(u8, 0b00000000) == 8);
147 try expect(ctz(u16, 0b00000000) == 16);
155 try expect(@ctz(u8, 0b10100000) == 5);
156 try expect(@ctz(u8, 0b10001010) == 1);
157 try expect(@ctz(u8, 0b00000000) == 8);
158 try expect(@ctz(u16, 0b00000000) == 16);
159}
160
161test "@ctz vectors" {
162 try testClzVectors();
163 comptime try testClzVectors();
148164}
149165
150fn ctz(comptime T: type, x: T) usize {
151 return @ctz(T, x);
166fn testCtzVectors() !void {
167 @setEvalBranchQuota(10_000);
168 try expectEqual(@ctz(u8, @splat(64, @as(u8, 0b10100000))), @splat(64, @as(u4, 5)));
169 try expectEqual(@ctz(u8, @splat(64, @as(u8, 0b10001010))), @splat(64, @as(u4, 1)));
170 try expectEqual(@ctz(u8, @splat(64, @as(u8, 0b00000000))), @splat(64, @as(u4, 8)));
171 try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16)));
152172}
153173
154174test "assignment operators" {