authorgravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2019-07-14 09:22:37-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-18 16:49:14-04:00
log76f53960778e84ab49730edb77b85490b07fbea2
tree9c14f9af00d722b3ebafc8462acf9a5f8e082663
parent86209e1a9259dca40803e56d612beacf5a35855c
signaturelock-open Commit is signed but in an unrecognized format.

@byteSwap on vectors


4 files changed, 85 insertions(+), 17 deletions(-)

src/all_types.hpp+1
...@@ -1771,6 +1771,7 @@ struct ZigLLVMFnKey {...@@ -1771,6 +1771,7 @@ struct ZigLLVMFnKey {
1771 } overflow_arithmetic;1771 } overflow_arithmetic;
1772 struct {1772 struct {
1773 uint32_t bit_count;1773 uint32_t bit_count;
1774 uint32_t vector_len; // 0 means not a vector
1774 } bswap;1775 } bswap;
1775 struct {1776 struct {
1776 uint32_t bit_count;1777 uint32_t bit_count;
src/codegen.cpp+21-7
...@@ -4505,7 +4505,13 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec...@@ -4505,7 +4505,13 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec
4505 }4505 }
4506}4506}
45074507
4508static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnId fn_id) {4508static 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 = 0;
4513 if (is_vector)
4514 vector_len = expr_type->data.vector.len;
4509 ZigLLVMFnKey key = {};4515 ZigLLVMFnKey key = {};
4510 const char *fn_name;4516 const char *fn_name;
4511 uint32_t n_args;4517 uint32_t n_args;
...@@ -4529,6 +4535,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI...@@ -4529,6 +4535,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
4529 n_args = 1;4535 n_args = 1;
4530 key.id = ZigLLVMFnIdBswap;4536 key.id = ZigLLVMFnIdBswap;
4531 key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count;4537 key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count;
4538 key.data.bswap.vector_len = vector_len;
4532 } else if (fn_id == BuiltinFnIdBitReverse) {4539 } else if (fn_id == BuiltinFnIdBitReverse) {
4533 fn_name = "bitreverse";4540 fn_name = "bitreverse";
4534 n_args = 1;4541 n_args = 1;
...@@ -4543,12 +4550,15 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI...@@ -4543,12 +4550,15 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
4543 return existing_entry->value;4550 return existing_entry->value;
45444551
4545 char llvm_name[64];4552 char llvm_name[64];
4546 sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count);4553 if (is_vector)
4554 sprintf(llvm_name, "llvm.%s.v%" PRIu32 "i%" PRIu32, fn_name, vector_len, int_type->data.integral.bit_count);
4555 else
4556 sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count);
4547 LLVMTypeRef param_types[] = {4557 LLVMTypeRef param_types[] = {
4548 get_llvm_type(g, int_type),4558 get_llvm_type(g, expr_type),
4549 LLVMInt1Type(),4559 LLVMInt1Type(),
4550 };4560 };
4551 LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, int_type), param_types, n_args, false);4561 LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, expr_type), param_types, n_args, false);
4552 LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);4562 LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);
4553 assert(LLVMGetIntrinsicID(fn_val));4563 assert(LLVMGetIntrinsicID(fn_val));
45544564
...@@ -5542,15 +5552,19 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn...@@ -5542,15 +5552,19 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn
55425552
5543static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {5553static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
5544 LLVMValueRef op = ir_llvm_value(g, instruction->op);5554 LLVMValueRef op = ir_llvm_value(g, instruction->op);
5545 ZigType *int_type = instruction->base.value.type;5555 ZigType *expr_type = instruction->base.value.type;
5556 bool is_vector = expr_type->id == ZigTypeIdVector;
5557 ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type;
5546 assert(int_type->id == ZigTypeIdInt);5558 assert(int_type->id == ZigTypeIdInt);
5547 if (int_type->data.integral.bit_count % 16 == 0) {5559 if (int_type->data.integral.bit_count % 16 == 0) {
5548 LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap);5560 LLVMValueRef fn_val = get_int_builtin_fn(g, expr_type, BuiltinFnIdBswap);
5549 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");5561 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
5550 }5562 }
5551 // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate5563 // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate
5552 ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed,5564 ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed,
5553 int_type->data.integral.bit_count + 8);5565 int_type->data.integral.bit_count + 8);
5566 if (is_vector)
5567 extended_type = get_vector_type(g, expr_type->data.vector.len, extended_type);
5554 // aabbcc5568 // aabbcc
5555 LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), "");5569 LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), "");
5556 // 00aabbcc5570 // 00aabbcc
...@@ -5560,7 +5574,7 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst...@@ -5560,7 +5574,7 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst
5560 LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped,5574 LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped,
5561 LLVMConstInt(get_llvm_type(g, extended_type), 8, false), "");5575 LLVMConstInt(get_llvm_type(g, extended_type), 8, false), "");
5562 // 00ccbbaa5576 // 00ccbbaa
5563 return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, int_type), "");5577 return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), "");
5564}5578}
55655579
5566static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) {5580static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) {
src/ir.cpp+52-10
...@@ -25253,16 +25253,42 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct...@@ -25253,16 +25253,42 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct
25253}25253}
2525425254
25255static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) {25255static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) {
25256 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);25256 IrInstruction *op = instruction->op->child;
25257 if (type_is_invalid(int_type))25257 ZigType *type_expr = ir_resolve_type(ira, instruction->type->child);
25258 if (type_is_invalid(type_expr))
25258 return ira->codegen->invalid_instruction;25259 return ira->codegen->invalid_instruction;
2525925260
25260 IrInstruction *op = ir_implicit_cast(ira, instruction->op->child, int_type);25261 if (type_expr->id != ZigTypeIdInt) {
25262 ir_add_error(ira, instruction->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;
25270 }
25271 ZigType *int_type = type_expr;
25272
25273 ZigType *expr_type = op->value.type;
25274 bool is_vector = expr_type->id == ZigTypeIdVector;
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
25279 op = ir_implicit_cast(ira, instruction->op->child, ret_type);
25261 if (type_is_invalid(op->value.type))25280 if (type_is_invalid(op->value.type))
25262 return ira->codegen->invalid_instruction;25281 return ira->codegen->invalid_instruction;
2526325282
25264 if (int_type->data.integral.bit_count == 0) {25283 if (int_type->data.integral.bit_count == 0) {
25265 IrInstruction *result = ir_const(ira, &instruction->base, int_type);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 }
25266 bigint_init_unsigned(&result->value.data.x_bigint, 0);25292 bigint_init_unsigned(&result->value.data.x_bigint, 0);
25267 return result;25293 return result;
25268 }25294 }
...@@ -25282,20 +25308,36 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction...@@ -25282,20 +25308,36 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction
25282 if (val == nullptr)25308 if (val == nullptr)
25283 return ira->codegen->invalid_instruction;25309 return ira->codegen->invalid_instruction;
25284 if (val->special == ConstValSpecialUndef)25310 if (val->special == ConstValSpecialUndef)
25285 return ir_const_undef(ira, &instruction->base, int_type);25311 return ir_const_undef(ira, &instruction->base, ret_type);
2528625312
25287 IrInstruction *result = ir_const(ira, &instruction->base, int_type);25313 IrInstruction *result = ir_const(ira, &instruction->base, ret_type);
25288 size_t buf_size = int_type->data.integral.bit_count / 8;25314 size_t buf_size = int_type->data.integral.bit_count / 8;
25289 uint8_t *buf = allocate_nonzero<uint8_t>(buf_size);25315 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);25316 if (is_vector) {
25291 bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false,25317 expand_undef_array(ira->codegen, &result->value);
25292 int_type->data.integral.is_signed);25318 result->value.data.x_array.data.s_none.elements =
25319 allocate<ConstExprValue>(expr_type->data.vector.len);
25320 for (unsigned i = 0; i < expr_type->data.vector.len; i++) {
25321 ConstExprValue *cur = &val->data.x_array.data.s_none.elements[i];
25322 result->value.data.x_array.data.s_none.elements[i].special = cur->special;
25323 if (cur->special == ConstValSpecialUndef)
25324 continue;
25325 bigint_write_twos_complement(&cur->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,
25327 buf, int_type->data.integral.bit_count, false,
25328 int_type->data.integral.is_signed);
25329 }
25330 } else {
25331 bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true);
25332 bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false,
25333 int_type->data.integral.is_signed);
25334 }
25293 return result;25335 return result;
25294 }25336 }
2529525337
25296 IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope,25338 IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope,
25297 instruction->base.source_node, nullptr, op);25339 instruction->base.source_node, nullptr, op);
25298 result->value.type = int_type;25340 result->value.type = ret_type;
25299 return result;25341 return result;
25300}25342}
2530125343
test/stage1/behavior/byteswap.zig+11
...@@ -6,6 +6,11 @@ test "@byteSwap" {...@@ -6,6 +6,11 @@ test "@byteSwap" {
6 testByteSwap();6 testByteSwap();
7}7}
88
9test "@byteSwap on vectors" {
10 comptime testVectorByteSwap();
11 testVectorByteSwap();
12}
13
9fn testByteSwap() void {14fn testByteSwap() void {
10 expect(@byteSwap(u0, 0) == 0);15 expect(@byteSwap(u0, 0) == 0);
11 expect(@byteSwap(u8, 0x12) == 0x12);16 expect(@byteSwap(u8, 0x12) == 0x12);
...@@ -30,3 +35,9 @@ fn testByteSwap() void {...@@ -30,3 +35,9 @@ fn testByteSwap() void {
30 expect(@byteSwap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==35 expect(@byteSwap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
31 @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));36 @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
32}37}
38
39fn testVectorByteSwap() void {
40 expect((@byteSwap(u8, @Vector(2, u8)([2]u8{0x12, 0x13})) == @Vector(2, u8)([2]u8{0x12, 0x13})).all);
41 expect((@byteSwap(u16, @Vector(2, u16)([2]u16{0x1234, 0x2345})) == @Vector(2, u16)([2]u16{0x3412, 0x4523})).all);
42 expect((@byteSwap(u24, @Vector(2, u24)([2]u24{0x123456, 0x234567})) == @Vector(2, u24)([2]u24{0x563412, 0x674523})).all);
43}