Skip to content

Commit 0a3aec0

Browse files
LemonBoyandrewrk
authored andcommitted
Fix load/store of non-integer fields in packed struct
1 parent 51aaa02 commit 0a3aec0

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

src/codegen.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

34033415
static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {

test/stage1/behavior/struct.zig

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const std = @import("std");
22
const expect = std.testing.expect;
3+
const expectEqual = std.testing.expectEqual;
34
const expectEqualSlices = std.testing.expectEqualSlices;
45
const builtin = @import("builtin");
5-
const maxInt = std.math.maxInt;
6+
const maxInt = std.math.maxInt;
67
const 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

508-
const S0 = struct{
509+
const 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+
528+
test "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+
}

0 commit comments

Comments
 (0)