| author | |
| committer | |
| log | f6cd68386d76e4a9a489187c47f218b59e1734f3 |
| tree | 016fbfe6ceff6e7535bc55c27735e8723ee037de |
| parent | 6df8e4bca73309f2e340dbfa9031f1bb16a73bcc |
* bitreverse - give bswap behavior
* bitreverse, comptime_ints, negative values still not working?
* bitreverse working for negative comptime ints
* Finished bitreverse test cases
* Undo exporting a bigint function. @bitreverse test name includes ampersand
* added docs entry for @bitreverse
9 files changed, 240 insertions(+), 1 deletions(-)
doc/langref.html.in+12| ... | @@ -5316,6 +5316,18 @@ comptime { | ... | @@ -5316,6 +5316,18 @@ comptime { |
| 5316 | </p> | 5316 | </p> |
| 5317 | {#header_close#} | 5317 | {#header_close#} |
| 5318 | 5318 | ||
| 5319 | {#header_open|@bitreverse#} | ||
| 5320 | <pre>{#syntax#}@bitreverse(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 5321 | <p>{#syntax#}T{#endsyntax#} accepts any integer type.</p> | ||
| 5322 | <p> | ||
| 5323 | Reverses the bitpattern of an integer value, including the sign bit if applicable. | ||
| 5324 | </p> | ||
| 5325 | <p> | ||
| 5326 | For example 0b10110110 ({#syntax#}u8 = 182{#endsyntax#}, {#syntax#}i8 = -74{#endsyntax#}) | ||
| 5327 | becomes 0b01101101 ({#syntax#}u8 = 109{#endsyntax#}, {#syntax#}i8 = 109{#endsyntax#}). | ||
| 5328 | </p> | ||
| 5329 | {#header_close#} | ||
| 5330 | |||
| 5319 | {#header_open|@byteOffsetOf#} | 5331 | {#header_open|@byteOffsetOf#} |
| 5320 | <pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre> | 5332 | <pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre> |
| 5321 | <p> | 5333 | <p> |
src/all_types.hpp+13| ... | @@ -1415,6 +1415,7 @@ enum BuiltinFnId { | ... | @@ -1415,6 +1415,7 @@ enum BuiltinFnId { |
| 1415 | BuiltinFnIdAtomicRmw, | 1415 | BuiltinFnIdAtomicRmw, |
| 1416 | BuiltinFnIdAtomicLoad, | 1416 | BuiltinFnIdAtomicLoad, |
| 1417 | BuiltinFnIdBswap, | 1417 | BuiltinFnIdBswap, |
| 1418 | BuiltinFnIdBitReverse, | ||
| 1418 | }; | 1419 | }; |
| 1419 | 1420 | ||
| 1420 | struct BuiltinFnEntry { | 1421 | struct BuiltinFnEntry { |
| ... | @@ -1488,6 +1489,7 @@ enum ZigLLVMFnId { | ... | @@ -1488,6 +1489,7 @@ enum ZigLLVMFnId { |
| 1488 | ZigLLVMFnIdCeil, | 1489 | ZigLLVMFnIdCeil, |
| 1489 | ZigLLVMFnIdSqrt, | 1490 | ZigLLVMFnIdSqrt, |
| 1490 | ZigLLVMFnIdBswap, | 1491 | ZigLLVMFnIdBswap, |
| 1492 | ZigLLVMFnIdBitReverse, | ||
| 1491 | }; | 1493 | }; |
| 1492 | 1494 | ||
| 1493 | enum AddSubMul { | 1495 | enum AddSubMul { |
| ... | @@ -1520,6 +1522,9 @@ struct ZigLLVMFnKey { | ... | @@ -1520,6 +1522,9 @@ struct ZigLLVMFnKey { |
| 1520 | struct { | 1522 | struct { |
| 1521 | uint32_t bit_count; | 1523 | uint32_t bit_count; |
| 1522 | } bswap; | 1524 | } bswap; |
| 1525 | struct { | ||
| 1526 | uint32_t bit_count; | ||
| 1527 | } bit_reverse; | ||
| 1523 | } data; | 1528 | } data; |
| 1524 | }; | 1529 | }; |
| 1525 | 1530 | ||
| ... | @@ -2162,6 +2167,7 @@ enum IrInstructionId { | ... | @@ -2162,6 +2167,7 @@ enum IrInstructionId { |
| 2162 | IrInstructionIdMarkErrRetTracePtr, | 2167 | IrInstructionIdMarkErrRetTracePtr, |
| 2163 | IrInstructionIdSqrt, | 2168 | IrInstructionIdSqrt, |
| 2164 | IrInstructionIdBswap, | 2169 | IrInstructionIdBswap, |
| 2170 | IrInstructionIdBitReverse, | ||
| 2165 | IrInstructionIdErrSetCast, | 2171 | IrInstructionIdErrSetCast, |
| 2166 | IrInstructionIdToBytes, | 2172 | IrInstructionIdToBytes, |
| 2167 | IrInstructionIdFromBytes, | 2173 | IrInstructionIdFromBytes, |
| ... | @@ -3262,6 +3268,13 @@ struct IrInstructionBswap { | ... | @@ -3262,6 +3268,13 @@ struct IrInstructionBswap { |
| 3262 | IrInstruction *op; | 3268 | IrInstruction *op; |
| 3263 | }; | 3269 | }; |
| 3264 | 3270 | ||
| 3271 | struct IrInstructionBitReverse { | ||
| 3272 | IrInstruction base; | ||
| 3273 | |||
| 3274 | IrInstruction *type; | ||
| 3275 | IrInstruction *op; | ||
| 3276 | }; | ||
| 3277 | |||
| 3265 | static const size_t slice_ptr_index = 0; | 3278 | static const size_t slice_ptr_index = 0; |
| 3266 | static const size_t slice_len_index = 1; | 3279 | static const size_t slice_len_index = 1; |
| 3267 | 3280 |
src/analyze.cpp+4| ... | @@ -6121,6 +6121,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { | ... | @@ -6121,6 +6121,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { |
| 6121 | return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; | 6121 | return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; |
| 6122 | case ZigLLVMFnIdBswap: | 6122 | case ZigLLVMFnIdBswap: |
| 6123 | return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; | 6123 | return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; |
| 6124 | case ZigLLVMFnIdBitReverse: | ||
| 6125 | return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; | ||
| 6124 | case ZigLLVMFnIdOverflowArithmetic: | 6126 | case ZigLLVMFnIdOverflowArithmetic: |
| 6125 | return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + | 6127 | return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + |
| 6126 | ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + | 6128 | ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + |
| ... | @@ -6141,6 +6143,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -6141,6 +6143,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6141 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; | 6143 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; |
| 6142 | case ZigLLVMFnIdBswap: | 6144 | case ZigLLVMFnIdBswap: |
| 6143 | return a.data.bswap.bit_count == b.data.bswap.bit_count; | 6145 | return a.data.bswap.bit_count == b.data.bswap.bit_count; |
| 6146 | case ZigLLVMFnIdBitReverse: | ||
| 6147 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; | ||
| 6144 | case ZigLLVMFnIdFloor: | 6148 | case ZigLLVMFnIdFloor: |
| 6145 | case ZigLLVMFnIdCeil: | 6149 | case ZigLLVMFnIdCeil: |
| 6146 | case ZigLLVMFnIdSqrt: | 6150 | case ZigLLVMFnIdSqrt: |
src/bigint.cpp+1| ... | @@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) { | ... | @@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) { |
| 1722 | 1722 | ||
| 1723 | bigint_add(x, &copy, &one); | 1723 | bigint_add(x, &copy, &one); |
| 1724 | } | 1724 | } |
| 1725 |
src/codegen.cpp+16| ... | @@ -3789,6 +3789,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI | ... | @@ -3789,6 +3789,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI |
| 3789 | n_args = 1; | 3789 | n_args = 1; |
| 3790 | key.id = ZigLLVMFnIdBswap; | 3790 | key.id = ZigLLVMFnIdBswap; |
| 3791 | key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; | 3791 | key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; |
| 3792 | } else if (fn_id == BuiltinFnIdBitReverse) { | ||
| 3793 | fn_name = "bitreverse"; | ||
| 3794 | n_args = 1; | ||
| 3795 | key.id = ZigLLVMFnIdBitReverse; | ||
| 3796 | key.data.bit_reverse.bit_count = (uint32_t)int_type->data.integral.bit_count; | ||
| 3792 | } else { | 3797 | } else { |
| 3793 | zig_unreachable(); | 3798 | zig_unreachable(); |
| 3794 | } | 3799 | } |
| ... | @@ -5096,6 +5101,14 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -5096,6 +5101,14 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst |
| 5096 | return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); | 5101 | return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); |
| 5097 | } | 5102 | } |
| 5098 | 5103 | ||
| 5104 | static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { | ||
| 5105 | LLVMValueRef op = ir_llvm_value(g, instruction->op); | ||
| 5106 | ZigType *int_type = instruction->base.value.type; | ||
| 5107 | assert(int_type->id == ZigTypeIdInt); | ||
| 5108 | LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBitReverse); | ||
| 5109 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); | ||
| 5110 | } | ||
| 5111 | |||
| 5099 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { | 5112 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 5100 | AstNode *source_node = instruction->source_node; | 5113 | AstNode *source_node = instruction->source_node; |
| 5101 | Scope *scope = instruction->scope; | 5114 | Scope *scope = instruction->scope; |
| ... | @@ -5335,6 +5348,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5335,6 +5348,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5335 | return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); | 5348 | return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); |
| 5336 | case IrInstructionIdBswap: | 5349 | case IrInstructionIdBswap: |
| 5337 | return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); | 5350 | return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); |
| 5351 | case IrInstructionIdBitReverse: | ||
| 5352 | return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); | ||
| 5338 | } | 5353 | } |
| 5339 | zig_unreachable(); | 5354 | zig_unreachable(); |
| 5340 | } | 5355 | } |
| ... | @@ -6758,6 +6773,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -6758,6 +6773,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 6758 | create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); | 6773 | create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); |
| 6759 | create_builtin_fn(g, BuiltinFnIdThis, "This", 0); | 6774 | create_builtin_fn(g, BuiltinFnIdThis, "This", 0); |
| 6760 | create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); | 6775 | create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); |
| 6776 | create_builtin_fn(g, BuiltinFnIdBitReverse, "bitreverse", 2); | ||
| 6761 | } | 6777 | } |
| 6762 | 6778 | ||
| 6763 | static const char *bool_to_str(bool b) { | 6779 | static const char *bool_to_str(bool b) { |
src/ir.cpp+97-1| ... | @@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { | ... | @@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { |
| 861 | return IrInstructionIdBswap; | 861 | return IrInstructionIdBswap; |
| 862 | } | 862 | } |
| 863 | 863 | ||
| 864 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitReverse *) { | ||
| 865 | return IrInstructionIdBitReverse; | ||
| 866 | } | ||
| 867 | |||
| 864 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { | 868 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { |
| 865 | return IrInstructionIdCheckRuntimeScope; | 869 | return IrInstructionIdCheckRuntimeScope; |
| 866 | } | 870 | } |
| ... | @@ -2721,6 +2725,17 @@ static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *sour | ... | @@ -2721,6 +2725,17 @@ static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *sour |
| 2721 | return &instruction->base; | 2725 | return &instruction->base; |
| 2722 | } | 2726 | } |
| 2723 | 2727 | ||
| 2728 | static IrInstruction *ir_build_bit_reverse(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { | ||
| 2729 | IrInstructionBitReverse *instruction = ir_build_instruction<IrInstructionBitReverse>(irb, scope, source_node); | ||
| 2730 | instruction->type = type; | ||
| 2731 | instruction->op = op; | ||
| 2732 | |||
| 2733 | if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); | ||
| 2734 | ir_ref_instruction(op, irb->current_basic_block); | ||
| 2735 | |||
| 2736 | return &instruction->base; | ||
| 2737 | } | ||
| 2738 | |||
| 2724 | static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { | 2739 | static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { |
| 2725 | IrInstructionCheckRuntimeScope *instruction = ir_build_instruction<IrInstructionCheckRuntimeScope>(irb, scope, source_node); | 2740 | IrInstructionCheckRuntimeScope *instruction = ir_build_instruction<IrInstructionCheckRuntimeScope>(irb, scope, source_node); |
| 2726 | instruction->scope_is_comptime = scope_is_comptime; | 2741 | instruction->scope_is_comptime = scope_is_comptime; |
| ... | @@ -3646,7 +3661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -3646,7 +3661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 3646 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; | 3661 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; |
| 3647 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); | 3662 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); |
| 3648 | 3663 | ||
| 3649 | if (!entry) { | 3664 | if (!entry) { // new built in not found |
| 3650 | add_node_error(irb->codegen, node, | 3665 | add_node_error(irb->codegen, node, |
| 3651 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); | 3666 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); |
| 3652 | return irb->codegen->invalid_instruction; | 3667 | return irb->codegen->invalid_instruction; |
| ... | @@ -4720,6 +4735,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4720,6 +4735,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4720 | IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); | 4735 | IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); |
| 4721 | return ir_lval_wrap(irb, scope, result, lval); | 4736 | return ir_lval_wrap(irb, scope, result, lval); |
| 4722 | } | 4737 | } |
| 4738 | case BuiltinFnIdBitReverse: | ||
| 4739 | { | ||
| 4740 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4741 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4742 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4743 | return arg0_value; | ||
| 4744 | |||
| 4745 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4746 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4747 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4748 | return arg1_value; | ||
| 4749 | |||
| 4750 | IrInstruction *result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value); | ||
| 4751 | return ir_lval_wrap(irb, scope, result, lval); | ||
| 4752 | } | ||
| 4723 | } | 4753 | } |
| 4724 | zig_unreachable(); | 4754 | zig_unreachable(); |
| 4725 | } | 4755 | } |
| ... | @@ -21115,6 +21145,69 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction | ... | @@ -21115,6 +21145,69 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction |
| 21115 | return result; | 21145 | return result; |
| 21116 | } | 21146 | } |
| 21117 | 21147 | ||
| 21148 | static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { | ||
| 21149 | ZigType *int_type = ir_resolve_type(ira, instruction->type->child); | ||
| 21150 | if (type_is_invalid(int_type)) | ||
| 21151 | return ira->codegen->invalid_instruction; | ||
| 21152 | |||
| 21153 | IrInstruction *op = instruction->op->child; | ||
| 21154 | if (type_is_invalid(op->value.type)) | ||
| 21155 | return ira->codegen->invalid_instruction; | ||
| 21156 | |||
| 21157 | if (int_type->id != ZigTypeIdInt) { | ||
| 21158 | ir_add_error(ira, instruction->type, | ||
| 21159 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); | ||
| 21160 | return ira->codegen->invalid_instruction; | ||
| 21161 | } | ||
| 21162 | |||
| 21163 | IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); | ||
| 21164 | if (type_is_invalid(casted_op->value.type)) | ||
| 21165 | return ira->codegen->invalid_instruction; | ||
| 21166 | |||
| 21167 | if (int_type->data.integral.bit_count == 0) { | ||
| 21168 | IrInstruction *result = ir_const(ira, &instruction->base, int_type); | ||
| 21169 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | ||
| 21170 | return result; | ||
| 21171 | } | ||
| 21172 | |||
| 21173 | if (instr_is_comptime(casted_op)) { | ||
| 21174 | ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); | ||
| 21175 | if (!val) | ||
| 21176 | return ira->codegen->invalid_instruction; | ||
| 21177 | |||
| 21178 | IrInstruction *result = ir_const(ira, &instruction->base, int_type); | ||
| 21179 | size_t num_bits = int_type->data.integral.bit_count; | ||
| 21180 | size_t buf_size = (num_bits + 7) / 8; | ||
| 21181 | uint8_t *comptime_buf = allocate_nonzero<uint8_t>(buf_size); | ||
| 21182 | uint8_t *result_buf = allocate_nonzero<uint8_t>(buf_size); | ||
| 21183 | memset(comptime_buf,0,buf_size); | ||
| 21184 | memset(result_buf,0,buf_size); | ||
| 21185 | |||
| 21186 | bigint_write_twos_complement(&val->data.x_bigint,comptime_buf,num_bits,ira->codegen->is_big_endian); | ||
| 21187 | |||
| 21188 | size_t bit_i = 0; | ||
| 21189 | size_t bit_rev_i = num_bits - 1; | ||
| 21190 | for (; bit_i < num_bits; bit_i++, bit_rev_i--) { | ||
| 21191 | if (comptime_buf[bit_i / 8] & (1 << (bit_i % 8))) { | ||
| 21192 | result_buf[bit_rev_i / 8] |= (1 << (bit_rev_i % 8)); | ||
| 21193 | } | ||
| 21194 | } | ||
| 21195 | |||
| 21196 | bigint_read_twos_complement(&result->value.data.x_bigint, | ||
| 21197 | result_buf, | ||
| 21198 | int_type->data.integral.bit_count, | ||
| 21199 | ira->codegen->is_big_endian, | ||
| 21200 | int_type->data.integral.is_signed); | ||
| 21201 | |||
| 21202 | return result; | ||
| 21203 | } | ||
| 21204 | |||
| 21205 | IrInstruction *result = ir_build_bit_reverse(&ira->new_irb, instruction->base.scope, | ||
| 21206 | instruction->base.source_node, nullptr, casted_op); | ||
| 21207 | result->value.type = int_type; | ||
| 21208 | return result; | ||
| 21209 | } | ||
| 21210 | |||
| 21118 | 21211 | ||
| 21119 | static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { | 21212 | static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { |
| 21120 | Error err; | 21213 | Error err; |
| ... | @@ -21453,6 +21546,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -21453,6 +21546,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 21453 | return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); | 21546 | return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); |
| 21454 | case IrInstructionIdBswap: | 21547 | case IrInstructionIdBswap: |
| 21455 | return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); | 21548 | return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); |
| 21549 | case IrInstructionIdBitReverse: | ||
| 21550 | return ir_analyze_instruction_bit_reverse(ira, (IrInstructionBitReverse *)instruction); | ||
| 21456 | case IrInstructionIdIntToErr: | 21551 | case IrInstructionIdIntToErr: |
| 21457 | return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); | 21552 | return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); |
| 21458 | case IrInstructionIdErrToInt: | 21553 | case IrInstructionIdErrToInt: |
| ... | @@ -21675,6 +21770,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -21675,6 +21770,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21675 | case IrInstructionIdPromiseResultType: | 21770 | case IrInstructionIdPromiseResultType: |
| 21676 | case IrInstructionIdSqrt: | 21771 | case IrInstructionIdSqrt: |
| 21677 | case IrInstructionIdBswap: | 21772 | case IrInstructionIdBswap: |
| 21773 | case IrInstructionIdBitReverse: | ||
| 21678 | case IrInstructionIdAtomicLoad: | 21774 | case IrInstructionIdAtomicLoad: |
| 21679 | case IrInstructionIdIntCast: | 21775 | case IrInstructionIdIntCast: |
| 21680 | case IrInstructionIdFloatCast: | 21776 | case IrInstructionIdFloatCast: |
src/ir_print.cpp+15| ... | @@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { | ... | @@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { |
| 1335 | fprintf(irp->f, ")"); | 1335 | fprintf(irp->f, ")"); |
| 1336 | } | 1336 | } |
| 1337 | 1337 | ||
| 1338 | static void ir_print_bit_reverse(IrPrint *irp, IrInstructionBitReverse *instruction) { | ||
| 1339 | fprintf(irp->f, "@bitreverse("); | ||
| 1340 | if (instruction->type != nullptr) { | ||
| 1341 | ir_print_other_instruction(irp, instruction->type); | ||
| 1342 | } else { | ||
| 1343 | fprintf(irp->f, "null"); | ||
| 1344 | } | ||
| 1345 | fprintf(irp->f, ","); | ||
| 1346 | ir_print_other_instruction(irp, instruction->op); | ||
| 1347 | fprintf(irp->f, ")"); | ||
| 1348 | } | ||
| 1349 | |||
| 1338 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1350 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1339 | ir_print_prefix(irp, instruction); | 1351 | ir_print_prefix(irp, instruction); |
| 1340 | switch (instruction->id) { | 1352 | switch (instruction->id) { |
| ... | @@ -1751,6 +1763,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1751,6 +1763,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1751 | case IrInstructionIdBswap: | 1763 | case IrInstructionIdBswap: |
| 1752 | ir_print_bswap(irp, (IrInstructionBswap *)instruction); | 1764 | ir_print_bswap(irp, (IrInstructionBswap *)instruction); |
| 1753 | break; | 1765 | break; |
| 1766 | case IrInstructionIdBitReverse: | ||
| 1767 | ir_print_bit_reverse(irp, (IrInstructionBitReverse *)instruction); | ||
| 1768 | break; | ||
| 1754 | case IrInstructionIdAtomicLoad: | 1769 | case IrInstructionIdAtomicLoad: |
| 1755 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); | 1770 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); |
| 1756 | break; | 1771 | break; |
test/behavior.zig+1| ... | @@ -9,6 +9,7 @@ comptime { | ... | @@ -9,6 +9,7 @@ comptime { |
| 9 | _ = @import("cases/bitcast.zig"); | 9 | _ = @import("cases/bitcast.zig"); |
| 10 | _ = @import("cases/bool.zig"); | 10 | _ = @import("cases/bool.zig"); |
| 11 | _ = @import("cases/bswap.zig"); | 11 | _ = @import("cases/bswap.zig"); |
| 12 | _ = @import("cases/bitreverse.zig"); | ||
| 12 | _ = @import("cases/bugs/1076.zig"); | 13 | _ = @import("cases/bugs/1076.zig"); |
| 13 | _ = @import("cases/bugs/1111.zig"); | 14 | _ = @import("cases/bugs/1111.zig"); |
| 14 | _ = @import("cases/bugs/1277.zig"); | 15 | _ = @import("cases/bugs/1277.zig"); |
test/cases/bitreverse.zig created+81| ... | @@ -0,0 +1,81 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const minInt = std.math.minInt; | ||
| 4 | |||
| 5 | test "@bitreverse" { | ||
| 6 | comptime testBitReverse(); | ||
| 7 | testBitReverse(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitReverse() void { | ||
| 11 | // using comptime_ints, unsigned | ||
| 12 | assert(@bitreverse(u0, 0) == 0); | ||
| 13 | assert(@bitreverse(u5, 0x12) == 0x9); | ||
| 14 | assert(@bitreverse(u8, 0x12) == 0x48); | ||
| 15 | assert(@bitreverse(u16, 0x1234) == 0x2c48); | ||
| 16 | assert(@bitreverse(u24, 0x123456) == 0x6a2c48); | ||
| 17 | assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); | ||
| 18 | assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); | ||
| 19 | assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); | ||
| 20 | assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); | ||
| 21 | assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); | ||
| 22 | assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 23 | |||
| 24 | // using runtime uints, unsigned | ||
| 25 | var num0: u0 = 0; | ||
| 26 | assert(@bitreverse(u0, num0) == 0); | ||
| 27 | var num5: u5 = 0x12; | ||
| 28 | assert(@bitreverse(u5, num5) == 0x9); | ||
| 29 | var num8: u8 = 0x12; | ||
| 30 | assert(@bitreverse(u8, num8) == 0x48); | ||
| 31 | var num16: u16 = 0x1234; | ||
| 32 | assert(@bitreverse(u16, num16) == 0x2c48); | ||
| 33 | var num24: u24 = 0x123456; | ||
| 34 | assert(@bitreverse(u24, num24) == 0x6a2c48); | ||
| 35 | var num32: u32 = 0x12345678; | ||
| 36 | assert(@bitreverse(u32, num32) == 0x1e6a2c48); | ||
| 37 | var num40: u40 = 0x123456789a; | ||
| 38 | assert(@bitreverse(u40, num40) == 0x591e6a2c48); | ||
| 39 | var num48: u48 = 0x123456789abc; | ||
| 40 | assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); | ||
| 41 | var num56: u56 = 0x123456789abcde; | ||
| 42 | assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); | ||
| 43 | var num64: u64 = 0x123456789abcdef1; | ||
| 44 | assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); | ||
| 45 | var num128: u128 = 0x123456789abcdef11121314151617181; | ||
| 46 | assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 47 | |||
| 48 | // using comptime_ints, signed, positive | ||
| 49 | assert(@bitreverse(i0, 0) == 0); | ||
| 50 | assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); | ||
| 51 | assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); | ||
| 52 | assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); | ||
| 53 | assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); | ||
| 54 | assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); | ||
| 55 | assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); | ||
| 56 | assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); | ||
| 57 | assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); | ||
| 58 | assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); | ||
| 59 | |||
| 60 | // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. | ||
| 61 | var neg5: i5 = minInt(i5) + 1; | ||
| 62 | assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); | ||
| 63 | var neg8: i8 = -18; | ||
| 64 | assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); | ||
| 65 | var neg16: i16 = -32694; | ||
| 66 | assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); | ||
| 67 | var neg24: i24 = -6773785; | ||
| 68 | assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); | ||
| 69 | var neg32: i32 = -16773785; | ||
| 70 | assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); | ||
| 71 | var neg40: i40 = minInt(i40) + 12345; | ||
| 72 | assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); | ||
| 73 | var neg48: i48 = minInt(i48) + 12345; | ||
| 74 | assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); | ||
| 75 | var neg56: i56 = minInt(i56) + 12345; | ||
| 76 | assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); | ||
| 77 | var neg64: i64 = minInt(i64) + 12345; | ||
| 78 | assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); | ||
| 79 | var neg128: i128 = minInt(i128) + 12345; | ||
| 80 | assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); | ||
| 81 | } | ||