Skip to content

Commit f6cd683

Browse files
justinbalexanderandrewrk
authored andcommitted
@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
1 parent 6df8e4b commit f6cd683

File tree

9 files changed

+240
-1
lines changed

9 files changed

+240
-1
lines changed

doc/langref.html.in

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,7 @@ enum BuiltinFnId {
14151415
BuiltinFnIdAtomicRmw,
14161416
BuiltinFnIdAtomicLoad,
14171417
BuiltinFnIdBswap,
1418+
BuiltinFnIdBitReverse,
14181419
};
14191420

14201421
struct BuiltinFnEntry {
@@ -1488,6 +1489,7 @@ enum ZigLLVMFnId {
14881489
ZigLLVMFnIdCeil,
14891490
ZigLLVMFnIdSqrt,
14901491
ZigLLVMFnIdBswap,
1492+
ZigLLVMFnIdBitReverse,
14911493
};
14921494

14931495
enum 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

3271+
struct IrInstructionBitReverse {
3272+
IrInstruction base;
3273+
3274+
IrInstruction *type;
3275+
IrInstruction *op;
3276+
};
3277+
32653278
static const size_t slice_ptr_index = 0;
32663279
static const size_t slice_len_index = 1;
32673280

src/analyze.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) {
17221722

17231723
bigint_add(x, &copy, &one);
17241724
}
1725+

src/codegen.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

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+
50995112
static 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

67636779
static const char *bool_to_str(bool b) {

src/ir.cpp

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) {
861861
return IrInstructionIdBswap;
862862
}
863863

864+
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitReverse *) {
865+
return IrInstructionIdBitReverse;
866+
}
867+
864868
static 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

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+
27242739
static 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

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+
2111821211

2111921212
static 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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
13351335
fprintf(irp->f, ")");
13361336
}
13371337

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+
13381350
static 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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)