| author | |
| committer | |
| log | 0048bcbd71b9139203d7acee120d524d38e22a0e |
| tree | 6f4139367553fea653662d1fb65bd23421bad77a |
| parent | 86209e1a9259dca40803e56d612beacf5a35855c |
| parent | 380c8ec2c95fa8d732c141c705d9940629eb2012 |
| signature |
This is the commit from Shawn's SIMD patchset regarding `@byteSwap`,
plus my fixups.6 files changed, 160 insertions(+), 54 deletions(-)
doc/langref.html.in+10-1| ... | ... | @@ -6542,12 +6542,21 @@ async fn func(y: *i32) void { |
| 6542 | 6542 | {#header_close#} |
| 6543 | 6543 | |
| 6544 | 6544 | {#header_open|@byteSwap#} |
| 6545 | <pre>{#syntax#}@byteSwap(comptime T: type, integer: T) T{#endsyntax#}</pre> | |
| 6545 | <pre>{#syntax#}@byteSwap(comptime T: type, operand: T) T{#endsyntax#}</pre> | |
| 6546 | 6546 | <p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p> |
| 6547 | <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p> | |
| 6547 | 6548 | <p> |
| 6548 | 6549 | Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, |
| 6549 | 6550 | and converts a little endian integer to a big endian integer. |
| 6550 | 6551 | </p> |
| 6552 | <p> | |
| 6553 | Note that for the purposes of memory layout with respect to endianness, the integer type should be | |
| 6554 | related to the number of bytes reported by {#link|@sizeOf#} bytes. This is demonstrated with | |
| 6555 | {#syntax#}u24{#endsyntax#}. {#syntax#}@sizeOf(u24) == 4{#endsyntax#}, which means that a | |
| 6556 | {#syntax#}u24{#endsyntax#} stored in memory takes 4 bytes, and those 4 bytes are what are swapped on | |
| 6557 | a little vs big endian system. On the other hand, if {#syntax#}T{#endsyntax#} is specified to | |
| 6558 | be {#syntax#}u24{#endsyntax#}, then only 3 bytes are reversed. | |
| 6559 | </p> | |
| 6551 | 6560 | {#header_close#} |
| 6552 | 6561 | |
| 6553 | 6562 | {#header_open|@bitReverse#} |
src/all_types.hpp+1| ... | ... | @@ -1771,6 +1771,7 @@ struct ZigLLVMFnKey { |
| 1771 | 1771 | } overflow_arithmetic; |
| 1772 | 1772 | struct { |
| 1773 | 1773 | uint32_t bit_count; |
| 1774 | uint32_t vector_len; // 0 means not a vector | |
| 1774 | 1775 | } bswap; |
| 1775 | 1776 | struct { |
| 1776 | 1777 | uint32_t bit_count; |
src/analyze.cpp+4-2| ... | ... | @@ -6896,7 +6896,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { |
| 6896 | 6896 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 6897 | 6897 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); |
| 6898 | 6898 | case ZigLLVMFnIdBswap: |
| 6899 | return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; | |
| 6899 | return (uint32_t)(x.data.bswap.bit_count) * ((uint32_t)3661994335) + | |
| 6900 | (uint32_t)(x.data.bswap.vector_len) * (((uint32_t)x.id << 5) + 1025); | |
| 6900 | 6901 | case ZigLLVMFnIdBitReverse: |
| 6901 | 6902 | return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; |
| 6902 | 6903 | case ZigLLVMFnIdOverflowArithmetic: |
| ... | ... | @@ -6919,7 +6920,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6919 | 6920 | case ZigLLVMFnIdPopCount: |
| 6920 | 6921 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; |
| 6921 | 6922 | case ZigLLVMFnIdBswap: |
| 6922 | return a.data.bswap.bit_count == b.data.bswap.bit_count; | |
| 6923 | return a.data.bswap.bit_count == b.data.bswap.bit_count && | |
| 6924 | a.data.bswap.vector_len == b.data.bswap.vector_len; | |
| 6923 | 6925 | case ZigLLVMFnIdBitReverse: |
| 6924 | 6926 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; |
| 6925 | 6927 | case ZigLLVMFnIdFloatOp: |
src/codegen.cpp+31-12| ... | ... | @@ -4505,7 +4505,11 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec |
| 4505 | 4505 | } |
| 4506 | 4506 | } |
| 4507 | 4507 | |
| 4508 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnId fn_id) { | |
| 4508 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFnId fn_id) { | |
| 4509 | bool is_vector = expr_type->id == ZigTypeIdVector; | |
| 4510 | ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; | |
| 4511 | assert(int_type->id == ZigTypeIdInt); | |
| 4512 | uint32_t vector_len = is_vector ? expr_type->data.vector.len : 0; | |
| 4509 | 4513 | ZigLLVMFnKey key = {}; |
| 4510 | 4514 | const char *fn_name; |
| 4511 | 4515 | uint32_t n_args; |
| ... | ... | @@ -4529,6 +4533,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI |
| 4529 | 4533 | n_args = 1; |
| 4530 | 4534 | key.id = ZigLLVMFnIdBswap; |
| 4531 | 4535 | key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; |
| 4536 | key.data.bswap.vector_len = vector_len; | |
| 4532 | 4537 | } else if (fn_id == BuiltinFnIdBitReverse) { |
| 4533 | 4538 | fn_name = "bitreverse"; |
| 4534 | 4539 | n_args = 1; |
| ... | ... | @@ -4543,12 +4548,15 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI |
| 4543 | 4548 | return existing_entry->value; |
| 4544 | 4549 | |
| 4545 | 4550 | char llvm_name[64]; |
| 4546 | sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count); | |
| 4551 | if (is_vector) | |
| 4552 | sprintf(llvm_name, "llvm.%s.v%" PRIu32 "i%" PRIu32, fn_name, vector_len, int_type->data.integral.bit_count); | |
| 4553 | else | |
| 4554 | sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count); | |
| 4547 | 4555 | LLVMTypeRef param_types[] = { |
| 4548 | get_llvm_type(g, int_type), | |
| 4556 | get_llvm_type(g, expr_type), | |
| 4549 | 4557 | LLVMInt1Type(), |
| 4550 | 4558 | }; |
| 4551 | LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, int_type), param_types, n_args, false); | |
| 4559 | LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, expr_type), param_types, n_args, false); | |
| 4552 | 4560 | LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type); |
| 4553 | 4561 | assert(LLVMGetIntrinsicID(fn_val)); |
| 4554 | 4562 | |
| ... | ... | @@ -5542,25 +5550,36 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn |
| 5542 | 5550 | |
| 5543 | 5551 | static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { |
| 5544 | 5552 | LLVMValueRef op = ir_llvm_value(g, instruction->op); |
| 5545 | ZigType *int_type = instruction->base.value.type; | |
| 5553 | ZigType *expr_type = instruction->base.value.type; | |
| 5554 | bool is_vector = expr_type->id == ZigTypeIdVector; | |
| 5555 | ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; | |
| 5546 | 5556 | assert(int_type->id == ZigTypeIdInt); |
| 5547 | 5557 | if (int_type->data.integral.bit_count % 16 == 0) { |
| 5548 | LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap); | |
| 5558 | LLVMValueRef fn_val = get_int_builtin_fn(g, expr_type, BuiltinFnIdBswap); | |
| 5549 | 5559 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); |
| 5550 | 5560 | } |
| 5551 | 5561 | // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate |
| 5552 | 5562 | ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, |
| 5553 | 5563 | int_type->data.integral.bit_count + 8); |
| 5564 | LLVMValueRef shift_amt = LLVMConstInt(get_llvm_type(g, extended_type), 8, false); | |
| 5565 | if (is_vector) { | |
| 5566 | extended_type = get_vector_type(g, expr_type->data.vector.len, extended_type); | |
| 5567 | LLVMValueRef *values = allocate_nonzero<LLVMValueRef>(expr_type->data.vector.len); | |
| 5568 | for (uint32_t i = 0; i < expr_type->data.vector.len; i += 1) { | |
| 5569 | values[i] = shift_amt; | |
| 5570 | } | |
| 5571 | shift_amt = LLVMConstVector(values, expr_type->data.vector.len); | |
| 5572 | free(values); | |
| 5573 | } | |
| 5554 | 5574 | // aabbcc |
| 5555 | 5575 | LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); |
| 5556 | 5576 | // 00aabbcc |
| 5557 | 5577 | LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); |
| 5558 | 5578 | LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); |
| 5559 | 5579 | // ccbbaa00 |
| 5560 | LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, | |
| 5561 | LLVMConstInt(get_llvm_type(g, extended_type), 8, false), ""); | |
| 5580 | LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, shift_amt, ""); | |
| 5562 | 5581 | // 00ccbbaa |
| 5563 | return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, int_type), ""); | |
| 5582 | return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), ""); | |
| 5564 | 5583 | } |
| 5565 | 5584 | |
| 5566 | 5585 | static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { |
| ... | ... | @@ -5581,7 +5600,7 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab |
| 5581 | 5600 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); |
| 5582 | 5601 | |
| 5583 | 5602 | ZigType *elem_type = array_type->data.array.child_type; |
| 5584 | bool bitcast_ok = (elem_type->size_in_bits * 8) == elem_type->abi_size; | |
| 5603 | bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; | |
| 5585 | 5604 | if (bitcast_ok) { |
| 5586 | 5605 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, |
| 5587 | 5606 | LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); |
| ... | ... | @@ -5615,7 +5634,7 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab |
| 5615 | 5634 | LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type); |
| 5616 | 5635 | |
| 5617 | 5636 | ZigType *elem_type = vector_type->data.vector.elem_type; |
| 5618 | bool bitcast_ok = (elem_type->size_in_bits * 8) == elem_type->abi_size; | |
| 5637 | bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; | |
| 5619 | 5638 | if (bitcast_ok) { |
| 5620 | 5639 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, |
| 5621 | 5640 | LLVMPointerType(vector_type_ref, 0), ""); |
| ... | ... | @@ -8888,7 +8907,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa |
| 8888 | 8907 | args.append(g->framework_dirs.at(i)); |
| 8889 | 8908 | } |
| 8890 | 8909 | |
| 8891 | //note(dimenus): appending libc headers before c_headers breaks intrinsics | |
| 8910 | //note(dimenus): appending libc headers before c_headers breaks intrinsics | |
| 8892 | 8911 | //and other compiler specific items |
| 8893 | 8912 | // According to Rich Felker libc headers are supposed to go before C language headers. |
| 8894 | 8913 | args.append("-isystem"); |
src/ir.cpp+59-14| ... | ... | @@ -11068,8 +11068,15 @@ static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 11068 | 11068 | return ira->codegen->builtin_types.entry_invalid; |
| 11069 | 11069 | |
| 11070 | 11070 | if (ty->id != ZigTypeIdInt) { |
| 11071 | ir_add_error(ira, type_value, | |
| 11071 | ErrorMsg *msg = ir_add_error(ira, type_value, | |
| 11072 | 11072 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&ty->name))); |
| 11073 | if (ty->id == ZigTypeIdVector && | |
| 11074 | ty->data.vector.elem_type->id == ZigTypeIdInt) | |
| 11075 | { | |
| 11076 | add_error_note(ira->codegen, msg, type_value->source_node, | |
| 11077 | buf_sprintf("represent vectors with their element types, i.e. '%s'", | |
| 11078 | buf_ptr(&ty->data.vector.elem_type->name))); | |
| 11079 | } | |
| 11073 | 11080 | return ira->codegen->builtin_types.entry_invalid; |
| 11074 | 11081 | } |
| 11075 | 11082 | |
| ... | ... | @@ -25253,21 +25260,35 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct |
| 25253 | 25260 | } |
| 25254 | 25261 | |
| 25255 | 25262 | static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { |
| 25263 | Error err; | |
| 25264 | ||
| 25256 | 25265 | ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); |
| 25257 | 25266 | if (type_is_invalid(int_type)) |
| 25258 | 25267 | return ira->codegen->invalid_instruction; |
| 25259 | 25268 | |
| 25260 | IrInstruction *op = ir_implicit_cast(ira, instruction->op->child, int_type); | |
| 25261 | if (type_is_invalid(op->value.type)) | |
| 25269 | IrInstruction *uncasted_op = instruction->op->child; | |
| 25270 | if (type_is_invalid(uncasted_op->value.type)) | |
| 25262 | 25271 | return ira->codegen->invalid_instruction; |
| 25263 | 25272 | |
| 25264 | if (int_type->data.integral.bit_count == 0) { | |
| 25265 | IrInstruction *result = ir_const(ira, &instruction->base, int_type); | |
| 25266 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | |
| 25267 | return result; | |
| 25273 | uint32_t vector_len; // UINT32_MAX means not a vector | |
| 25274 | if (uncasted_op->value.type->id == ZigTypeIdArray && | |
| 25275 | is_valid_vector_elem_type(uncasted_op->value.type->data.array.child_type)) | |
| 25276 | { | |
| 25277 | vector_len = uncasted_op->value.type->data.array.len; | |
| 25278 | } else if (uncasted_op->value.type->id == ZigTypeIdVector) { | |
| 25279 | vector_len = uncasted_op->value.type->data.vector.len; | |
| 25280 | } else { | |
| 25281 | vector_len = UINT32_MAX; | |
| 25268 | 25282 | } |
| 25269 | 25283 | |
| 25270 | if (int_type->data.integral.bit_count == 8) | |
| 25284 | bool is_vector = (vector_len != UINT32_MAX); | |
| 25285 | ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; | |
| 25286 | ||
| 25287 | IrInstruction *op = ir_implicit_cast(ira, uncasted_op, op_type); | |
| 25288 | if (type_is_invalid(op->value.type)) | |
| 25289 | return ira->codegen->invalid_instruction; | |
| 25290 | ||
| 25291 | if (int_type->data.integral.bit_count == 8 || int_type->data.integral.bit_count == 0) | |
| 25271 | 25292 | return op; |
| 25272 | 25293 | |
| 25273 | 25294 | if (int_type->data.integral.bit_count % 8 != 0) { |
| ... | ... | @@ -25282,20 +25303,44 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction |
| 25282 | 25303 | if (val == nullptr) |
| 25283 | 25304 | return ira->codegen->invalid_instruction; |
| 25284 | 25305 | if (val->special == ConstValSpecialUndef) |
| 25285 | return ir_const_undef(ira, &instruction->base, int_type); | |
| 25306 | return ir_const_undef(ira, &instruction->base, op_type); | |
| 25286 | 25307 | |
| 25287 | IrInstruction *result = ir_const(ira, &instruction->base, int_type); | |
| 25308 | IrInstruction *result = ir_const(ira, &instruction->base, op_type); | |
| 25288 | 25309 | size_t buf_size = int_type->data.integral.bit_count / 8; |
| 25289 | 25310 | uint8_t *buf = allocate_nonzero<uint8_t>(buf_size); |
| 25290 | bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | |
| 25291 | bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, | |
| 25292 | int_type->data.integral.is_signed); | |
| 25311 | if (is_vector) { | |
| 25312 | expand_undef_array(ira->codegen, val); | |
| 25313 | result->value.data.x_array.data.s_none.elements = create_const_vals(op_type->data.vector.len); | |
| 25314 | for (unsigned i = 0; i < op_type->data.vector.len; i += 1) { | |
| 25315 | ConstExprValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; | |
| 25316 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, | |
| 25317 | op_elem_val, UndefOk))) | |
| 25318 | { | |
| 25319 | return ira->codegen->invalid_instruction; | |
| 25320 | } | |
| 25321 | ConstExprValue *result_elem_val = &result->value.data.x_array.data.s_none.elements[i]; | |
| 25322 | result_elem_val->type = int_type; | |
| 25323 | result_elem_val->special = op_elem_val->special; | |
| 25324 | if (op_elem_val->special == ConstValSpecialUndef) | |
| 25325 | continue; | |
| 25326 | ||
| 25327 | bigint_write_twos_complement(&op_elem_val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | |
| 25328 | bigint_read_twos_complement(&result->value.data.x_array.data.s_none.elements[i].data.x_bigint, | |
| 25329 | buf, int_type->data.integral.bit_count, false, | |
| 25330 | int_type->data.integral.is_signed); | |
| 25331 | } | |
| 25332 | } else { | |
| 25333 | bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | |
| 25334 | bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, | |
| 25335 | int_type->data.integral.is_signed); | |
| 25336 | } | |
| 25337 | free(buf); | |
| 25293 | 25338 | return result; |
| 25294 | 25339 | } |
| 25295 | 25340 | |
| 25296 | 25341 | IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, |
| 25297 | 25342 | instruction->base.source_node, nullptr, op); |
| 25298 | result->value.type = int_type; | |
| 25343 | result->value.type = op_type; | |
| 25299 | 25344 | return result; |
| 25300 | 25345 | } |
| 25301 | 25346 |
test/stage1/behavior/byteswap.zig+55-25| ... | ... | @@ -1,32 +1,62 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | 3 | |
| 4 | test "@byteSwap" { | |
| 5 | comptime testByteSwap(); | |
| 6 | testByteSwap(); | |
| 4 | test "@byteSwap integers" { | |
| 5 | const ByteSwapIntTest = struct { | |
| 6 | fn run() void { | |
| 7 | t(u0, 0, 0); | |
| 8 | t(u8, 0x12, 0x12); | |
| 9 | t(u16, 0x1234, 0x3412); | |
| 10 | t(u24, 0x123456, 0x563412); | |
| 11 | t(u32, 0x12345678, 0x78563412); | |
| 12 | t(u40, 0x123456789a, 0x9a78563412); | |
| 13 | t(i48, 0x123456789abc, @bitCast(i48, u48(0xbc9a78563412))); | |
| 14 | t(u56, 0x123456789abcde, 0xdebc9a78563412); | |
| 15 | t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); | |
| 16 | t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | |
| 17 | ||
| 18 | t(u0, u0(0), 0); | |
| 19 | t(i8, i8(-50), -50); | |
| 20 | t(i16, @bitCast(i16, u16(0x1234)), @bitCast(i16, u16(0x3412))); | |
| 21 | t(i24, @bitCast(i24, u24(0x123456)), @bitCast(i24, u24(0x563412))); | |
| 22 | t(i32, @bitCast(i32, u32(0x12345678)), @bitCast(i32, u32(0x78563412))); | |
| 23 | t(u40, @bitCast(i40, u40(0x123456789a)), u40(0x9a78563412)); | |
| 24 | t(i48, @bitCast(i48, u48(0x123456789abc)), @bitCast(i48, u48(0xbc9a78563412))); | |
| 25 | t(i56, @bitCast(i56, u56(0x123456789abcde)), @bitCast(i56, u56(0xdebc9a78563412))); | |
| 26 | t(i64, @bitCast(i64, u64(0x123456789abcdef1)), @bitCast(i64, u64(0xf1debc9a78563412))); | |
| 27 | t( | |
| 28 | i128, | |
| 29 | @bitCast(i128, u128(0x123456789abcdef11121314151617181)), | |
| 30 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)), | |
| 31 | ); | |
| 32 | } | |
| 33 | fn t(comptime I: type, input: I, expected_output: I) void { | |
| 34 | std.testing.expectEqual(expected_output, @byteSwap(I, input)); | |
| 35 | } | |
| 36 | }; | |
| 37 | comptime ByteSwapIntTest.run(); | |
| 38 | ByteSwapIntTest.run(); | |
| 7 | 39 | } |
| 8 | 40 | |
| 9 | fn testByteSwap() void { | |
| 10 | expect(@byteSwap(u0, 0) == 0); | |
| 11 | expect(@byteSwap(u8, 0x12) == 0x12); | |
| 12 | expect(@byteSwap(u16, 0x1234) == 0x3412); | |
| 13 | expect(@byteSwap(u24, 0x123456) == 0x563412); | |
| 14 | expect(@byteSwap(u32, 0x12345678) == 0x78563412); | |
| 15 | expect(@byteSwap(u40, 0x123456789a) == 0x9a78563412); | |
| 16 | expect(@byteSwap(i48, 0x123456789abc) == @bitCast(i48, u48(0xbc9a78563412))); | |
| 17 | expect(@byteSwap(u56, 0x123456789abcde) == 0xdebc9a78563412); | |
| 18 | expect(@byteSwap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); | |
| 19 | expect(@byteSwap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); | |
| 41 | test "@byteSwap vectors" { | |
| 42 | const ByteSwapVectorTest = struct { | |
| 43 | fn run() void { | |
| 44 | t(u8, 2, [_]u8{ 0x12, 0x13 }, [_]u8{ 0x12, 0x13 }); | |
| 45 | t(u16, 2, [_]u16{ 0x1234, 0x2345 }, [_]u16{ 0x3412, 0x4523 }); | |
| 46 | t(u24, 2, [_]u24{ 0x123456, 0x234567 }, [_]u24{ 0x563412, 0x674523 }); | |
| 47 | } | |
| 20 | 48 | |
| 21 | expect(@byteSwap(u0, u0(0)) == 0); | |
| 22 | expect(@byteSwap(i8, i8(-50)) == -50); | |
| 23 | expect(@byteSwap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); | |
| 24 | expect(@byteSwap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); | |
| 25 | expect(@byteSwap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); | |
| 26 | expect(@byteSwap(u40, @bitCast(i40, u40(0x123456789a))) == u40(0x9a78563412)); | |
| 27 | expect(@byteSwap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); | |
| 28 | expect(@byteSwap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); | |
| 29 | expect(@byteSwap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); | |
| 30 | expect(@byteSwap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == | |
| 31 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); | |
| 49 | fn t( | |
| 50 | comptime I: type, | |
| 51 | comptime n: comptime_int, | |
| 52 | input: @Vector(n, I), | |
| 53 | expected_vector: @Vector(n, I), | |
| 54 | ) void { | |
| 55 | const actual_output: [n]I = @byteSwap(I, input); | |
| 56 | const expected_output: [n]I = expected_vector; | |
| 57 | std.testing.expectEqual(expected_output, actual_output); | |
| 58 | } | |
| 59 | }; | |
| 60 | comptime ByteSwapVectorTest.run(); | |
| 61 | ByteSwapVectorTest.run(); | |
| 32 | 62 | } |