authorgravatar for 39607947+vegecode@users.noreply.github.comvegecode <39607947+vegecode@users.noreply.github.com> 2019-01-02 15:47:47-06:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-01-02 16:47:47-05:00
logf6cd68386d76e4a9a489187c47f218b59e1734f3
tree016fbfe6ceff6e7535bc55c27735e8723ee037de
parent6df8e4bca73309f2e340dbfa9031f1bb16a73bcc

@bitreverse intrinsic, part of #767 (#1865)

* 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 {
53165316 </p>
53175317 {#header_close#}
53185318
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
53195331 {#header_open|@byteOffsetOf#}
53205332 <pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
53215333 <p>
src/all_types.hpp+13
......@@ -1415,6 +1415,7 @@ enum BuiltinFnId {
14151415 BuiltinFnIdAtomicRmw,
14161416 BuiltinFnIdAtomicLoad,
14171417 BuiltinFnIdBswap,
1418 BuiltinFnIdBitReverse,
14181419};
14191420
14201421struct BuiltinFnEntry {
......@@ -1488,6 +1489,7 @@ enum ZigLLVMFnId {
14881489 ZigLLVMFnIdCeil,
14891490 ZigLLVMFnIdSqrt,
14901491 ZigLLVMFnIdBswap,
1492 ZigLLVMFnIdBitReverse,
14911493};
14921494
14931495enum AddSubMul {
......@@ -1520,6 +1522,9 @@ struct ZigLLVMFnKey {
15201522 struct {
15211523 uint32_t bit_count;
15221524 } bswap;
1525 struct {
1526 uint32_t bit_count;
1527 } bit_reverse;
15231528 } data;
15241529};
15251530
......@@ -2162,6 +2167,7 @@ enum IrInstructionId {
21622167 IrInstructionIdMarkErrRetTracePtr,
21632168 IrInstructionIdSqrt,
21642169 IrInstructionIdBswap,
2170 IrInstructionIdBitReverse,
21652171 IrInstructionIdErrSetCast,
21662172 IrInstructionIdToBytes,
21672173 IrInstructionIdFromBytes,
......@@ -3262,6 +3268,13 @@ struct IrInstructionBswap {
32623268 IrInstruction *op;
32633269};
32643270
3271struct IrInstructionBitReverse {
3272 IrInstruction base;
3273
3274 IrInstruction *type;
3275 IrInstruction *op;
3276};
3277
32653278static const size_t slice_ptr_index = 0;
32663279static const size_t slice_len_index = 1;
32673280
src/analyze.cpp+4
......@@ -6121,6 +6121,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
61216121 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
61226122 case ZigLLVMFnIdBswap:
61236123 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;
61246126 case ZigLLVMFnIdOverflowArithmetic:
61256127 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
61266128 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
......@@ -6141,6 +6143,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
61416143 return a.data.pop_count.bit_count == b.data.pop_count.bit_count;
61426144 case ZigLLVMFnIdBswap:
61436145 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;
61446148 case ZigLLVMFnIdFloor:
61456149 case ZigLLVMFnIdCeil:
61466150 case ZigLLVMFnIdSqrt:
src/bigint.cpp+1
......@@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) {
17221722
17231723 bigint_add(x, &copy, &one);
17241724}
1725
src/codegen.cpp+16
......@@ -3789,6 +3789,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
37893789 n_args = 1;
37903790 key.id = ZigLLVMFnIdBswap;
37913791 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;
37923797 } else {
37933798 zig_unreachable();
37943799 }
......@@ -5096,6 +5101,14 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst
50965101 return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, "");
50975102}
50985103
5104static 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
50995112static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
51005113 AstNode *source_node = instruction->source_node;
51015114 Scope *scope = instruction->scope;
......@@ -5335,6 +5348,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
53355348 return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
53365349 case IrInstructionIdBswap:
53375350 return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction);
5351 case IrInstructionIdBitReverse:
5352 return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction);
53385353 }
53395354 zig_unreachable();
53405355}
......@@ -6758,6 +6773,7 @@ static void define_builtin_fns(CodeGen *g) {
67586773 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
67596774 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
67606775 create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2);
6776 create_builtin_fn(g, BuiltinFnIdBitReverse, "bitreverse", 2);
67616777}
67626778
67636779static const char *bool_to_str(bool b) {
src/ir.cpp+97-1
......@@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) {
861861 return IrInstructionIdBswap;
862862}
863863
864static constexpr IrInstructionId ir_instruction_id(IrInstructionBitReverse *) {
865 return IrInstructionIdBitReverse;
866}
867
864868static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {
865869 return IrInstructionIdCheckRuntimeScope;
866870}
......@@ -2721,6 +2725,17 @@ static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *sour
27212725 return &instruction->base;
27222726}
27232727
2728static 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
27242739static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) {
27252740 IrInstructionCheckRuntimeScope *instruction = ir_build_instruction<IrInstructionCheckRuntimeScope>(irb, scope, source_node);
27262741 instruction->scope_is_comptime = scope_is_comptime;
......@@ -3646,7 +3661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
36463661 Buf *name = fn_ref_expr->data.symbol_expr.symbol;
36473662 auto entry = irb->codegen->builtin_fn_table.maybe_get(name);
36483663
3649 if (!entry) {
3664 if (!entry) { // new built in not found
36503665 add_node_error(irb->codegen, node,
36513666 buf_sprintf("invalid builtin function: '%s'", buf_ptr(name)));
36523667 return irb->codegen->invalid_instruction;
......@@ -4720,6 +4735,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
47204735 IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value);
47214736 return ir_lval_wrap(irb, scope, result, lval);
47224737 }
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 }
47234753 }
47244754 zig_unreachable();
47254755}
......@@ -21115,6 +21145,69 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction
2111521145 return result;
2111621146}
2111721147
21148static 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
2111821211
2111921212static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
2112021213 Error err;
......@@ -21453,6 +21546,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
2145321546 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);
2145421547 case IrInstructionIdBswap:
2145521548 return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction);
21549 case IrInstructionIdBitReverse:
21550 return ir_analyze_instruction_bit_reverse(ira, (IrInstructionBitReverse *)instruction);
2145621551 case IrInstructionIdIntToErr:
2145721552 return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);
2145821553 case IrInstructionIdErrToInt:
......@@ -21675,6 +21770,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2167521770 case IrInstructionIdPromiseResultType:
2167621771 case IrInstructionIdSqrt:
2167721772 case IrInstructionIdBswap:
21773 case IrInstructionIdBitReverse:
2167821774 case IrInstructionIdAtomicLoad:
2167921775 case IrInstructionIdIntCast:
2168021776 case IrInstructionIdFloatCast:
src/ir_print.cpp+15
......@@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
13351335 fprintf(irp->f, ")");
13361336}
13371337
1338static 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
13381350static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13391351 ir_print_prefix(irp, instruction);
13401352 switch (instruction->id) {
......@@ -1751,6 +1763,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
17511763 case IrInstructionIdBswap:
17521764 ir_print_bswap(irp, (IrInstructionBswap *)instruction);
17531765 break;
1766 case IrInstructionIdBitReverse:
1767 ir_print_bit_reverse(irp, (IrInstructionBitReverse *)instruction);
1768 break;
17541769 case IrInstructionIdAtomicLoad:
17551770 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
17561771 break;
test/behavior.zig+1
......@@ -9,6 +9,7 @@ comptime {
99 _ = @import("cases/bitcast.zig");
1010 _ = @import("cases/bool.zig");
1111 _ = @import("cases/bswap.zig");
12 _ = @import("cases/bitreverse.zig");
1213 _ = @import("cases/bugs/1076.zig");
1314 _ = @import("cases/bugs/1111.zig");
1415 _ = @import("cases/bugs/1277.zig");
test/cases/bitreverse.zig created+81
......@@ -0,0 +1,81 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const minInt = std.math.minInt;
4
5test "@bitreverse" {
6 comptime testBitReverse();
7 testBitReverse();
8}
9
10fn 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}