| author | |
| committer | |
| log | 380c8ec2c95fa8d732c141c705d9940629eb2012 |
| tree | 6f4139367553fea653662d1fb65bd23421bad77a |
| parent | 76f53960778e84ab49730edb77b85490b07fbea2 |
| signature |
* update docs for `@byteSwap`.
* fix hash & eql functions for ZigLLVMFnIdBswap not updated to
include vector len. this was causing incorrect bswap function
being called in unrelated code
* fix `@byteSwap` behavior tests only testing comptime and not
runtime operations
* implement runtime `@byteSwap`
* fix incorrect logic in ir_render_vector_to_array and
ir_render_array_to_vector with regards to whether or not to bitcast
* `@byteSwap` accepts an array operand which it will cast to vector
* simplify `@byteSwap` semantic analysis code and various fixes5 files changed, 129 insertions(+), 91 deletions(-)
doc/langref.html.in+10-1| ... | @@ -6542,12 +6542,21 @@ async fn func(y: *i32) void { | ... | @@ -6542,12 +6542,21 @@ async fn func(y: *i32) void { |
| 6542 | {#header_close#} | 6542 | {#header_close#} |
| 6543 | 6543 | ||
| 6544 | {#header_open|@byteSwap#} | 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 | <p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p> | 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 | <p> | 6548 | <p> |
| 6548 | Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, | 6549 | Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, |
| 6549 | and converts a little endian integer to a big endian integer. | 6550 | and converts a little endian integer to a big endian integer. |
| 6550 | </p> | 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 | {#header_close#} | 6560 | {#header_close#} |
| 6552 | 6561 | ||
| 6553 | {#header_open|@bitReverse#} | 6562 | {#header_open|@bitReverse#} |
src/analyze.cpp+4-2| ... | @@ -6896,7 +6896,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { | ... | @@ -6896,7 +6896,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { |
| 6896 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + | 6896 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 6897 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); | 6897 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); |
| 6898 | case ZigLLVMFnIdBswap: | 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 | case ZigLLVMFnIdBitReverse: | 6901 | case ZigLLVMFnIdBitReverse: |
| 6901 | return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; | 6902 | return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; |
| 6902 | case ZigLLVMFnIdOverflowArithmetic: | 6903 | case ZigLLVMFnIdOverflowArithmetic: |
| ... | @@ -6919,7 +6920,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -6919,7 +6920,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6919 | case ZigLLVMFnIdPopCount: | 6920 | case ZigLLVMFnIdPopCount: |
| 6920 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; | 6921 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; |
| 6921 | case ZigLLVMFnIdBswap: | 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 | case ZigLLVMFnIdBitReverse: | 6925 | case ZigLLVMFnIdBitReverse: |
| 6924 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; | 6926 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; |
| 6925 | case ZigLLVMFnIdFloatOp: | 6927 | case ZigLLVMFnIdFloatOp: |
src/codegen.cpp+14-9| ... | @@ -4509,9 +4509,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFn | ... | @@ -4509,9 +4509,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFn |
| 4509 | bool is_vector = expr_type->id == ZigTypeIdVector; | 4509 | bool is_vector = expr_type->id == ZigTypeIdVector; |
| 4510 | ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; | 4510 | ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; |
| 4511 | assert(int_type->id == ZigTypeIdInt); | 4511 | assert(int_type->id == ZigTypeIdInt); |
| 4512 | uint32_t vector_len = 0; | 4512 | uint32_t vector_len = is_vector ? expr_type->data.vector.len : 0; |
| 4513 | if (is_vector) | ||
| 4514 | vector_len = expr_type->data.vector.len; | ||
| 4515 | ZigLLVMFnKey key = {}; | 4513 | ZigLLVMFnKey key = {}; |
| 4516 | const char *fn_name; | 4514 | const char *fn_name; |
| 4517 | uint32_t n_args; | 4515 | uint32_t n_args; |
| ... | @@ -5563,16 +5561,23 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -5563,16 +5561,23 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst |
| 5563 | // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate | 5561 | // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate |
| 5564 | ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, | 5562 | ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, |
| 5565 | int_type->data.integral.bit_count + 8); | 5563 | int_type->data.integral.bit_count + 8); |
| 5566 | if (is_vector) | 5564 | LLVMValueRef shift_amt = LLVMConstInt(get_llvm_type(g, extended_type), 8, false); |
| 5565 | if (is_vector) { | ||
| 5567 | extended_type = get_vector_type(g, expr_type->data.vector.len, extended_type); | 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 | } | ||
| 5568 | // aabbcc | 5574 | // aabbcc |
| 5569 | LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); | 5575 | LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); |
| 5570 | // 00aabbcc | 5576 | // 00aabbcc |
| 5571 | LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); | 5577 | LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); |
| 5572 | LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); | 5578 | LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); |
| 5573 | // ccbbaa00 | 5579 | // ccbbaa00 |
| 5574 | LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, | 5580 | LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, shift_amt, ""); |
| 5575 | LLVMConstInt(get_llvm_type(g, extended_type), 8, false), ""); | ||
| 5576 | // 00ccbbaa | 5581 | // 00ccbbaa |
| 5577 | return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), ""); | 5582 | return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), ""); |
| 5578 | } | 5583 | } |
| ... | @@ -5595,7 +5600,7 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab | ... | @@ -5595,7 +5600,7 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab |
| 5595 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); | 5600 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); |
| 5596 | 5601 | ||
| 5597 | ZigType *elem_type = array_type->data.array.child_type; | 5602 | ZigType *elem_type = array_type->data.array.child_type; |
| 5598 | 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; |
| 5599 | if (bitcast_ok) { | 5604 | if (bitcast_ok) { |
| 5600 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, | 5605 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, |
| 5601 | LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); | 5606 | LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); |
| ... | @@ -5629,7 +5634,7 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab | ... | @@ -5629,7 +5634,7 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab |
| 5629 | LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type); | 5634 | LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type); |
| 5630 | 5635 | ||
| 5631 | ZigType *elem_type = vector_type->data.vector.elem_type; | 5636 | ZigType *elem_type = vector_type->data.vector.elem_type; |
| 5632 | 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; |
| 5633 | if (bitcast_ok) { | 5638 | if (bitcast_ok) { |
| 5634 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, | 5639 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, |
| 5635 | LLVMPointerType(vector_type_ref, 0), ""); | 5640 | LLVMPointerType(vector_type_ref, 0), ""); |
| ... | @@ -8902,7 +8907,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa | ... | @@ -8902,7 +8907,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa |
| 8902 | args.append(g->framework_dirs.at(i)); | 8907 | args.append(g->framework_dirs.at(i)); |
| 8903 | } | 8908 | } |
| 8904 | 8909 | ||
| 8905 | //note(dimenus): appending libc headers before c_headers breaks intrinsics | 8910 | //note(dimenus): appending libc headers before c_headers breaks intrinsics |
| 8906 | //and other compiler specific items | 8911 | //and other compiler specific items |
| 8907 | // According to Rich Felker libc headers are supposed to go before C language headers. | 8912 | // According to Rich Felker libc headers are supposed to go before C language headers. |
| 8908 | args.append("-isystem"); | 8913 | args.append("-isystem"); |
src/ir.cpp+47-44| ... | @@ -11068,8 +11068,15 @@ static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { | ... | @@ -11068,8 +11068,15 @@ static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 11068 | return ira->codegen->builtin_types.entry_invalid; | 11068 | return ira->codegen->builtin_types.entry_invalid; |
| 11069 | 11069 | ||
| 11070 | if (ty->id != ZigTypeIdInt) { | 11070 | if (ty->id != ZigTypeIdInt) { |
| 11071 | ir_add_error(ira, type_value, | 11071 | ErrorMsg *msg = ir_add_error(ira, type_value, |
| 11072 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&ty->name))); | 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 | return ira->codegen->builtin_types.entry_invalid; | 11080 | return ira->codegen->builtin_types.entry_invalid; |
| 11074 | } | 11081 | } |
| 11075 | 11082 | ||
| ... | @@ -25253,47 +25260,35 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct | ... | @@ -25253,47 +25260,35 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct |
| 25253 | } | 25260 | } |
| 25254 | 25261 | ||
| 25255 | static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { | 25262 | static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { |
| 25256 | IrInstruction *op = instruction->op->child; | 25263 | Error err; |
| 25257 | ZigType *type_expr = ir_resolve_type(ira, instruction->type->child); | 25264 | |
| 25258 | if (type_is_invalid(type_expr)) | 25265 | ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); |
| 25266 | if (type_is_invalid(int_type)) | ||
| 25259 | return ira->codegen->invalid_instruction; | 25267 | return ira->codegen->invalid_instruction; |
| 25260 | 25268 | ||
| 25261 | if (type_expr->id != ZigTypeIdInt) { | 25269 | IrInstruction *uncasted_op = instruction->op->child; |
| 25262 | ir_add_error(ira, instruction->type, | 25270 | if (type_is_invalid(uncasted_op->value.type)) |
| 25263 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&type_expr->name))); | ||
| 25264 | if (type_expr->id == ZigTypeIdVector && | ||
| 25265 | type_expr->data.vector.elem_type->id == ZigTypeIdInt) | ||
| 25266 | ir_add_error(ira, instruction->type, | ||
| 25267 | buf_sprintf("represent vectors with their scalar types, i.e. '%s'", | ||
| 25268 | buf_ptr(&type_expr->data.vector.elem_type->name))); | ||
| 25269 | return ira->codegen->invalid_instruction; | 25271 | return ira->codegen->invalid_instruction; |
| 25272 | |||
| 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; | ||
| 25270 | } | 25282 | } |
| 25271 | ZigType *int_type = type_expr; | ||
| 25272 | 25283 | ||
| 25273 | ZigType *expr_type = op->value.type; | 25284 | bool is_vector = (vector_len != UINT32_MAX); |
| 25274 | bool is_vector = expr_type->id == ZigTypeIdVector; | 25285 | ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; |
| 25275 | ZigType *ret_type = int_type; | ||
| 25276 | if (is_vector) | ||
| 25277 | ret_type = get_vector_type(ira->codegen, expr_type->data.vector.len, int_type); | ||
| 25278 | 25286 | ||
| 25279 | op = ir_implicit_cast(ira, instruction->op->child, ret_type); | 25287 | IrInstruction *op = ir_implicit_cast(ira, uncasted_op, op_type); |
| 25280 | if (type_is_invalid(op->value.type)) | 25288 | if (type_is_invalid(op->value.type)) |
| 25281 | return ira->codegen->invalid_instruction; | 25289 | return ira->codegen->invalid_instruction; |
| 25282 | 25290 | ||
| 25283 | if (int_type->data.integral.bit_count == 0) { | 25291 | if (int_type->data.integral.bit_count == 8 || int_type->data.integral.bit_count == 0) |
| 25284 | IrInstruction *result = ir_const(ira, &instruction->base, ret_type); | ||
| 25285 | if (is_vector) { | ||
| 25286 | expand_undef_array(ira->codegen, &result->value); | ||
| 25287 | result->value.data.x_array.data.s_none.elements = | ||
| 25288 | allocate<ConstExprValue>(expr_type->data.vector.len); | ||
| 25289 | for (unsigned i = 0; i < expr_type->data.vector.len; i++) | ||
| 25290 | bigint_init_unsigned(&result->value.data.x_array.data.s_none.elements[i].data.x_bigint, 0); | ||
| 25291 | } | ||
| 25292 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | ||
| 25293 | return result; | ||
| 25294 | } | ||
| 25295 | |||
| 25296 | if (int_type->data.integral.bit_count == 8) | ||
| 25297 | return op; | 25292 | return op; |
| 25298 | 25293 | ||
| 25299 | if (int_type->data.integral.bit_count % 8 != 0) { | 25294 | if (int_type->data.integral.bit_count % 8 != 0) { |
| ... | @@ -25308,21 +25303,28 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction | ... | @@ -25308,21 +25303,28 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction |
| 25308 | if (val == nullptr) | 25303 | if (val == nullptr) |
| 25309 | return ira->codegen->invalid_instruction; | 25304 | return ira->codegen->invalid_instruction; |
| 25310 | if (val->special == ConstValSpecialUndef) | 25305 | if (val->special == ConstValSpecialUndef) |
| 25311 | return ir_const_undef(ira, &instruction->base, ret_type); | 25306 | return ir_const_undef(ira, &instruction->base, op_type); |
| 25312 | 25307 | ||
| 25313 | IrInstruction *result = ir_const(ira, &instruction->base, ret_type); | 25308 | IrInstruction *result = ir_const(ira, &instruction->base, op_type); |
| 25314 | size_t buf_size = int_type->data.integral.bit_count / 8; | 25309 | size_t buf_size = int_type->data.integral.bit_count / 8; |
| 25315 | uint8_t *buf = allocate_nonzero<uint8_t>(buf_size); | 25310 | uint8_t *buf = allocate_nonzero<uint8_t>(buf_size); |
| 25316 | if (is_vector) { | 25311 | if (is_vector) { |
| 25317 | expand_undef_array(ira->codegen, &result->value); | 25312 | expand_undef_array(ira->codegen, val); |
| 25318 | result->value.data.x_array.data.s_none.elements = | 25313 | result->value.data.x_array.data.s_none.elements = create_const_vals(op_type->data.vector.len); |
| 25319 | allocate<ConstExprValue>(expr_type->data.vector.len); | 25314 | for (unsigned i = 0; i < op_type->data.vector.len; i += 1) { |
| 25320 | for (unsigned i = 0; i < expr_type->data.vector.len; i++) { | 25315 | ConstExprValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; |
| 25321 | ConstExprValue *cur = &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, |
| 25322 | result->value.data.x_array.data.s_none.elements[i].special = cur->special; | 25317 | op_elem_val, UndefOk))) |
| 25323 | if (cur->special == ConstValSpecialUndef) | 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) | ||
| 25324 | continue; | 25325 | continue; |
| 25325 | bigint_write_twos_complement(&cur->data.x_bigint, buf, int_type->data.integral.bit_count, true); | 25326 | |
| 25327 | bigint_write_twos_complement(&op_elem_val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | ||
| 25326 | bigint_read_twos_complement(&result->value.data.x_array.data.s_none.elements[i].data.x_bigint, | 25328 | bigint_read_twos_complement(&result->value.data.x_array.data.s_none.elements[i].data.x_bigint, |
| 25327 | buf, int_type->data.integral.bit_count, false, | 25329 | buf, int_type->data.integral.bit_count, false, |
| 25328 | int_type->data.integral.is_signed); | 25330 | int_type->data.integral.is_signed); |
| ... | @@ -25332,12 +25334,13 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction | ... | @@ -25332,12 +25334,13 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction |
| 25332 | bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, | 25334 | bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, |
| 25333 | int_type->data.integral.is_signed); | 25335 | int_type->data.integral.is_signed); |
| 25334 | } | 25336 | } |
| 25337 | free(buf); | ||
| 25335 | return result; | 25338 | return result; |
| 25336 | } | 25339 | } |
| 25337 | 25340 | ||
| 25338 | IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, | 25341 | IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, |
| 25339 | instruction->base.source_node, nullptr, op); | 25342 | instruction->base.source_node, nullptr, op); |
| 25340 | result->value.type = ret_type; | 25343 | result->value.type = op_type; |
| 25341 | return result; | 25344 | return result; |
| 25342 | } | 25345 | } |
| 25343 | 25346 |
test/stage1/behavior/byteswap.zig+54-35| ... | @@ -1,43 +1,62 @@ | ... | @@ -1,43 +1,62 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | 3 | ||
| 4 | test "@byteSwap" { | 4 | test "@byteSwap integers" { |
| 5 | comptime testByteSwap(); | 5 | const ByteSwapIntTest = struct { |
| 6 | testByteSwap(); | 6 | fn run() void { |
| 7 | } | 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); | ||
| 8 | 17 | ||
| 9 | test "@byteSwap on vectors" { | 18 | t(u0, u0(0), 0); |
| 10 | comptime testVectorByteSwap(); | 19 | t(i8, i8(-50), -50); |
| 11 | testVectorByteSwap(); | 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(); | ||
| 12 | } | 39 | } |
| 13 | 40 | ||
| 14 | fn testByteSwap() void { | 41 | test "@byteSwap vectors" { |
| 15 | expect(@byteSwap(u0, 0) == 0); | 42 | const ByteSwapVectorTest = struct { |
| 16 | expect(@byteSwap(u8, 0x12) == 0x12); | 43 | fn run() void { |
| 17 | expect(@byteSwap(u16, 0x1234) == 0x3412); | 44 | t(u8, 2, [_]u8{ 0x12, 0x13 }, [_]u8{ 0x12, 0x13 }); |
| 18 | expect(@byteSwap(u24, 0x123456) == 0x563412); | 45 | t(u16, 2, [_]u16{ 0x1234, 0x2345 }, [_]u16{ 0x3412, 0x4523 }); |
| 19 | expect(@byteSwap(u32, 0x12345678) == 0x78563412); | 46 | t(u24, 2, [_]u24{ 0x123456, 0x234567 }, [_]u24{ 0x563412, 0x674523 }); |
| 20 | expect(@byteSwap(u40, 0x123456789a) == 0x9a78563412); | 47 | } |
| 21 | expect(@byteSwap(i48, 0x123456789abc) == @bitCast(i48, u48(0xbc9a78563412))); | ||
| 22 | expect(@byteSwap(u56, 0x123456789abcde) == 0xdebc9a78563412); | ||
| 23 | expect(@byteSwap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); | ||
| 24 | expect(@byteSwap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); | ||
| 25 | |||
| 26 | expect(@byteSwap(u0, u0(0)) == 0); | ||
| 27 | expect(@byteSwap(i8, i8(-50)) == -50); | ||
| 28 | expect(@byteSwap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); | ||
| 29 | expect(@byteSwap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); | ||
| 30 | expect(@byteSwap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); | ||
| 31 | expect(@byteSwap(u40, @bitCast(i40, u40(0x123456789a))) == u40(0x9a78563412)); | ||
| 32 | expect(@byteSwap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); | ||
| 33 | expect(@byteSwap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); | ||
| 34 | expect(@byteSwap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); | ||
| 35 | expect(@byteSwap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == | ||
| 36 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); | ||
| 37 | } | ||
| 38 | 48 | ||
| 39 | fn testVectorByteSwap() void { | 49 | fn t( |
| 40 | expect((@byteSwap(u8, @Vector(2, u8)([2]u8{0x12, 0x13})) == @Vector(2, u8)([2]u8{0x12, 0x13})).all); | 50 | comptime I: type, |
| 41 | expect((@byteSwap(u16, @Vector(2, u16)([2]u16{0x1234, 0x2345})) == @Vector(2, u16)([2]u16{0x3412, 0x4523})).all); | 51 | comptime n: comptime_int, |
| 42 | expect((@byteSwap(u24, @Vector(2, u24)([2]u24{0x123456, 0x234567})) == @Vector(2, u24)([2]u24{0x563412, 0x674523})).all); | 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(); | ||
| 43 | } | 62 | } |