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 {...@@ -1907,9 +1907,11 @@ struct ZigLLVMFnKey {
1907 union {1907 union {
1908 struct {1908 struct {
1909 uint32_t bit_count;1909 uint32_t bit_count;
1910 uint32_t vector_len; // 0 means not a vector
1910 } ctz;1911 } ctz;
1911 struct {1912 struct {
1912 uint32_t bit_count;1913 uint32_t bit_count;
1914 uint32_t vector_len; // 0 means not a vector
1913 } clz;1915 } clz;
1914 struct {1916 struct {
1915 uint32_t bit_count;1917 uint32_t bit_count;
src/stage1/analyze.cpp+4-2
...@@ -7883,9 +7883,11 @@ bool type_id_eql(TypeId const *a, TypeId const *b) {...@@ -7883,9 +7883,11 @@ bool type_id_eql(TypeId const *a, TypeId const *b) {
7883uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) {7883uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) {
7884 switch (x->id) {7884 switch (x->id) {
7885 case ZigLLVMFnIdCtz:7885 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);
7887 case ZigLLVMFnIdClz:7888 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);
7889 case ZigLLVMFnIdPopCount:7891 case ZigLLVMFnIdPopCount:
7890 return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 +7892 return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 +
7891 (uint32_t)(x->data.pop_count.vector_len) * (((uint32_t)x->id << 5) + 1025);7893 (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,...@@ -15945,54 +15945,154 @@ static Stage1AirInst *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira,
15945}15945}
1594615946
15947static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) {15947static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) {
15948 Error err;
15949
15948 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);15950 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);
15949 if (type_is_invalid(int_type))15951 if (type_is_invalid(int_type))
15950 return ira->codegen->invalid_inst_gen;15952 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);
15953 if (type_is_invalid(op->value->type))15977 if (type_is_invalid(op->value->type))
15954 return ira->codegen->invalid_inst_gen;15978 return ira->codegen->invalid_inst_gen;
1595515979
15956 if (int_type->data.integral.bit_count == 0)15980 if (int_type->data.integral.bit_count == 0)
15957 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0);15981 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
15959 if (instr_is_comptime(op)) {15985 if (instr_is_comptime(op)) {
15960 ZigValue *val = ir_resolve_const(ira, op, UndefOk);15986 ZigValue *val = ir_resolve_const(ira, op, UndefOk);
15961 if (val == nullptr)15987 if (val == nullptr)
15962 return ira->codegen->invalid_inst_gen;15988 return ira->codegen->invalid_inst_gen;
15963 if (val->special == ConstValSpecialUndef)15989 if (val->special == ConstValSpecialUndef)
15964 return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int);15990 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);15991
15966 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize);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 }
15967 }16017 }
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;
15970 return ir_build_ctz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);16020 return ir_build_ctz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);
15971}16021}
1597216022
15973static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) {16023static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) {
16024 Error err;
16025
15974 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);16026 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);
15975 if (type_is_invalid(int_type))16027 if (type_is_invalid(int_type))
15976 return ira->codegen->invalid_inst_gen;16028 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);
15979 if (type_is_invalid(op->value->type))16053 if (type_is_invalid(op->value->type))
15980 return ira->codegen->invalid_inst_gen;16054 return ira->codegen->invalid_inst_gen;
1598116055
15982 if (int_type->data.integral.bit_count == 0)16056 if (int_type->data.integral.bit_count == 0)
15983 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0);16057 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
15985 if (instr_is_comptime(op)) {16061 if (instr_is_comptime(op)) {
15986 ZigValue *val = ir_resolve_const(ira, op, UndefOk);16062 ZigValue *val = ir_resolve_const(ira, op, UndefOk);
15987 if (val == nullptr)16063 if (val == nullptr)
15988 return ira->codegen->invalid_inst_gen;16064 return ira->codegen->invalid_inst_gen;
15989 if (val->special == ConstValSpecialUndef)16065 if (val->special == ConstValSpecialUndef)
15990 return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int);16066 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);16067
15992 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize);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 }
15993 }16093 }
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;
15996 return ir_build_clz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);16096 return ir_build_clz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);
15997}16097}
1599816098
test/behavior/math.zig+34-14
...@@ -123,16 +123,27 @@ test "@clz" {...@@ -123,16 +123,27 @@ test "@clz" {
123}123}
124124
125fn testClz() !void {125fn testClz() !void {
126 try expect(clz(u8, 0b10001010) == 0);126 try expect(@clz(u8, 0b10001010) == 0);
127 try expect(clz(u8, 0b00001010) == 4);127 try expect(@clz(u8, 0b00001010) == 4);
128 try expect(clz(u8, 0b00011010) == 3);128 try expect(@clz(u8, 0b00011010) == 3);
129 try expect(clz(u8, 0b00000000) == 8);129 try expect(@clz(u8, 0b00000000) == 8);
130 try expect(clz(u128, 0xffffffffffffffff) == 64);130 try expect(@clz(u128, 0xffffffffffffffff) == 64);
131 try expect(clz(u128, 0x10000000000000000) == 63);131 try expect(@clz(u128, 0x10000000000000000) == 63);
132}132}
133133
134fn clz(comptime T: type, x: T) usize {134test "@clz vectors" {
135 return @clz(T, x);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)));
136}147}
137148
138test "@ctz" {149test "@ctz" {
...@@ -141,14 +152,23 @@ test "@ctz" {...@@ -141,14 +152,23 @@ test "@ctz" {
141}152}
142153
143fn testCtz() !void {154fn testCtz() !void {
144 try expect(ctz(u8, 0b10100000) == 5);155 try expect(@ctz(u8, 0b10100000) == 5);
145 try expect(ctz(u8, 0b10001010) == 1);156 try expect(@ctz(u8, 0b10001010) == 1);
146 try expect(ctz(u8, 0b00000000) == 8);157 try expect(@ctz(u8, 0b00000000) == 8);
147 try expect(ctz(u16, 0b00000000) == 16);158 try expect(@ctz(u16, 0b00000000) == 16);
159}
160
161test "@ctz vectors" {
162 try testClzVectors();
163 comptime try testClzVectors();
148}164}
149165
150fn ctz(comptime T: type, x: T) usize {166fn testCtzVectors() !void {
151 return @ctz(T, x);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)));
152}172}
153173
154test "assignment operators" {174test "assignment operators" {