| author | |
| committer | |
| log | f880af369d4814df7cd1ec0ef5f85343108bbe81 |
| tree | 61c5348ebf815a1233b5dc0829aa96a00447c2a1 |
| parent | dfc7493dcb049788b92137ca09b8bd47cee23865 |
3 files changed, 43 insertions(+), 0 deletions(-)
src/codegen/llvm.zig+18| ... | @@ -3646,6 +3646,24 @@ pub const DeclGen = struct { | ... | @@ -3646,6 +3646,24 @@ pub const DeclGen = struct { |
| 3646 | }, | 3646 | }, |
| 3647 | .Struct => { | 3647 | .Struct => { |
| 3648 | const field_ty = parent_ty.structFieldType(field_index); | 3648 | const field_ty = parent_ty.structFieldType(field_index); |
| 3649 | if (parent_ty.containerLayout() == .Packed) { | ||
| 3650 | const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); | ||
| 3651 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); | ||
| 3652 | // count bits of fields before this one | ||
| 3653 | const prev_bits = b: { | ||
| 3654 | var b: usize = 0; | ||
| 3655 | for (parent_ty.structFields().values()[0..field_index]) |field| { | ||
| 3656 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | ||
| 3657 | b += field.ty.bitSize(target); | ||
| 3658 | } | ||
| 3659 | break :b b; | ||
| 3660 | }; | ||
| 3661 | const byte_offset = llvm_usize.constInt((prev_bits + 7) / 8, .False); | ||
| 3662 | const field_addr = base_addr.constAdd(byte_offset); | ||
| 3663 | bitcast_needed = false; | ||
| 3664 | const final_llvm_ty = (try dg.lowerType(ptr_child_ty)).pointerType(0); | ||
| 3665 | break :blk field_addr.constIntToPtr(final_llvm_ty); | ||
| 3666 | } | ||
| 3649 | bitcast_needed = !field_ty.eql(ptr_child_ty, dg.module); | 3667 | bitcast_needed = !field_ty.eql(ptr_child_ty, dg.module); |
| 3650 | 3668 | ||
| 3651 | var ty_buf: Type.Payload.Pointer = undefined; | 3669 | var ty_buf: Type.Payload.Pointer = undefined; |
src/codegen/llvm/bindings.zig+3| ... | @@ -169,6 +169,9 @@ pub const Value = opaque { | ... | @@ -169,6 +169,9 @@ pub const Value = opaque { |
| 169 | pub const constNot = LLVMConstNot; | 169 | pub const constNot = LLVMConstNot; |
| 170 | extern fn LLVMConstNot(ConstantVal: *const Value) *const Value; | 170 | extern fn LLVMConstNot(ConstantVal: *const Value) *const Value; |
| 171 | 171 | ||
| 172 | pub const constAdd = LLVMConstAdd; | ||
| 173 | extern fn LLVMConstAdd(LHSConstant: *const Value, RHSConstant: *const Value) *const Value; | ||
| 174 | |||
| 172 | pub const setWeak = LLVMSetWeak; | 175 | pub const setWeak = LLVMSetWeak; |
| 173 | extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void; | 176 | extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void; |
| 174 | 177 |
test/behavior/packed-struct.zig+22| ... | @@ -436,3 +436,25 @@ test "load pointer from packed struct" { | ... | @@ -436,3 +436,25 @@ test "load pointer from packed struct" { |
| 436 | try expect(i == 123); | 436 | try expect(i == 123); |
| 437 | } | 437 | } |
| 438 | } | 438 | } |
| 439 | |||
| 440 | test "@ptrToInt on a packed struct field" { | ||
| 441 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | ||
| 442 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | ||
| 443 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 444 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 445 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 446 | |||
| 447 | const S = struct { | ||
| 448 | const P = packed struct { | ||
| 449 | x: u8, | ||
| 450 | y: u8, | ||
| 451 | z: u32, | ||
| 452 | }; | ||
| 453 | var p0: P = P{ | ||
| 454 | .x = 1, | ||
| 455 | .y = 2, | ||
| 456 | .z = 0, | ||
| 457 | }; | ||
| 458 | }; | ||
| 459 | try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2); | ||
| 460 | } |