authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-05-18 17:20:20+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-18 19:59:47-04:00
log0a3aec020a6c24e82e8b0accfd8d1a78286f4eda
tree9956a9086d42ce271e7c16a63ec6347c3d559aea
parent51aaa02679002ba65b270414bf94860fdcbe7c59

Fix load/store of non-integer fields in packed struct


2 files changed, 48 insertions(+), 14 deletions(-)

src/codegen.cpp+23-11
...@@ -1972,13 +1972,18 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty...@@ -1972,13 +1972,18 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
1972 uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset;1972 uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset;
1973 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);1973 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
19741974
1975 LLVMValueRef mask_val = LLVMConstAllOnes(get_llvm_type(g, child_type));1975 // Convert to equally-sized integer type in order to perform the bit
1976 // operations on the value to store
1977 LLVMTypeRef value_bits_type = LLVMIntType(size_in_bits);
1978 LLVMValueRef value_bits = LLVMBuildBitCast(g->builder, value, value_bits_type, "");
1979
1980 LLVMValueRef mask_val = LLVMConstAllOnes(value_bits_type);
1976 mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));1981 mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));
1977 mask_val = LLVMConstShl(mask_val, shift_amt_val);1982 mask_val = LLVMConstShl(mask_val, shift_amt_val);
1978 mask_val = LLVMConstNot(mask_val);1983 mask_val = LLVMConstNot(mask_val);
19791984
1980 LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, "");1985 LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, "");
1981 LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value, LLVMTypeOf(containing_int), "");1986 LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value_bits, LLVMTypeOf(containing_int), "");
1982 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");1987 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
1983 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");1988 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
19841989
...@@ -3388,16 +3393,23 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -3388,16 +3393,23 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
3388 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);3393 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
3389 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");3394 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
33903395
3391 if (!handle_is_ptr(child_type))3396 if (handle_is_ptr(child_type)) {
3392 return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), "");3397 assert(instruction->tmp_ptr != nullptr);
3398 LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
3399 LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
3400 LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
3401 LLVMPointerType(same_size_int, 0), "");
3402 LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
3403 return instruction->tmp_ptr;
3404 }
33933405
3394 assert(instruction->tmp_ptr != nullptr);3406 if (child_type->id == ZigTypeIdFloat) {
3395 LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);3407 LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
3396 LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");3408 LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
3397 LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,3409 return LLVMBuildBitCast(g->builder, truncated_int, get_llvm_type(g, child_type), "");
3398 LLVMPointerType(same_size_int, 0), "");3410 }
3399 LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);3411
3400 return instruction->tmp_ptr;3412 return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), "");
3401}3413}
34023414
3403static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {3415static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {
test/stage1/behavior/struct.zig+25-3
...@@ -1,8 +1,9 @@...@@ -1,8 +1,9 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
3const expectEqualSlices = std.testing.expectEqualSlices;4const expectEqualSlices = std.testing.expectEqualSlices;
4const builtin = @import("builtin");5const builtin = @import("builtin");
5const maxInt = std.math.maxInt; 6const maxInt = std.math.maxInt;
6const StructWithNoFields = struct {7const StructWithNoFields = struct {
7 fn add(a: i32, b: i32) i32 {8 fn add(a: i32, b: i32) i32 {
8 return a + b;9 return a + b;
...@@ -505,10 +506,10 @@ test "packed struct with u0 field access" {...@@ -505,10 +506,10 @@ test "packed struct with u0 field access" {
505 comptime expect(s.f0 == 0);506 comptime expect(s.f0 == 0);
506}507}
507508
508const S0 = struct{509const S0 = struct {
509 bar: S1,510 bar: S1,
510511
511 pub const S1 = struct{512 pub const S1 = struct {
512 value: u8,513 value: u8,
513 };514 };
514515
...@@ -523,3 +524,24 @@ test "access to global struct fields" {...@@ -523,3 +524,24 @@ test "access to global struct fields" {
523 g_foo.bar.value = 42;524 g_foo.bar.value = 42;
524 expect(g_foo.bar.value == 42);525 expect(g_foo.bar.value == 42);
525}526}
527
528test "packed struct with fp fields" {
529 const S = packed struct {
530 data: [3]f32,
531
532 pub fn frob(self: *@This()) void {
533 self.data[0] += self.data[1] + self.data[2];
534 self.data[1] += self.data[0] + self.data[2];
535 self.data[2] += self.data[0] + self.data[1];
536 }
537 };
538
539 var s: S = undefined;
540 s.data[0] = 1.0;
541 s.data[1] = 2.0;
542 s.data[2] = 3.0;
543 s.frob();
544 expectEqual(f32(6.0), s.data[0]);
545 expectEqual(f32(11.0), s.data[1]);
546 expectEqual(f32(20.0), s.data[2]);
547}