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
19721972 uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset;
19731973 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);
19761981 mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));
19771982 mask_val = LLVMConstShl(mask_val, shift_amt_val);
19781983 mask_val = LLVMConstNot(mask_val);
19791984
19801985 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), "");
19821987 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
19831988 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
33883393 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
33893394 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
33903395
3391 if (!handle_is_ptr(child_type))
3392 return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), "");
3396 if (handle_is_ptr(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);
3395 LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
3396 LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
3397 LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
3398 LLVMPointerType(same_size_int, 0), "");
3399 LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
3400 return instruction->tmp_ptr;
3406 if (child_type->id == ZigTypeIdFloat) {
3407 LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
3408 LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
3409 return LLVMBuildBitCast(g->builder, truncated_int, get_llvm_type(g, child_type), "");
3410 }
3411
3412 return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), "");
34013413}
34023414
34033415static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {
test/stage1/behavior/struct.zig+25-3
......@@ -1,8 +1,9 @@
11const std = @import("std");
22const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
34const expectEqualSlices = std.testing.expectEqualSlices;
45const builtin = @import("builtin");
5const maxInt = std.math.maxInt;
6const maxInt = std.math.maxInt;
67const StructWithNoFields = struct {
78 fn add(a: i32, b: i32) i32 {
89 return a + b;
......@@ -505,10 +506,10 @@ test "packed struct with u0 field access" {
505506 comptime expect(s.f0 == 0);
506507}
507508
508const S0 = struct{
509const S0 = struct {
509510 bar: S1,
510511
511 pub const S1 = struct{
512 pub const S1 = struct {
512513 value: u8,
513514 };
514515
......@@ -523,3 +524,24 @@ test "access to global struct fields" {
523524 g_foo.bar.value = 42;
524525 expect(g_foo.bar.value == 42);
525526}
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}