diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index e7915e08b3..6ebe76fb39 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3646,6 +3646,24 @@ pub const DeclGen = struct { }, .Struct => { const field_ty = parent_ty.structFieldType(field_index); + if (parent_ty.containerLayout() == .Packed) { + const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); + const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); + // count bits of fields before this one + const prev_bits = b: { + var b: usize = 0; + for (parent_ty.structFields().values()[0..field_index]) |field| { + if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; + b += field.ty.bitSize(target); + } + break :b b; + }; + const byte_offset = llvm_usize.constInt((prev_bits + 7) / 8, .False); + const field_addr = base_addr.constAdd(byte_offset); + bitcast_needed = false; + const final_llvm_ty = (try dg.lowerType(ptr_child_ty)).pointerType(0); + break :blk field_addr.constIntToPtr(final_llvm_ty); + } bitcast_needed = !field_ty.eql(ptr_child_ty, dg.module); var ty_buf: Type.Payload.Pointer = undefined; diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 07408f12b9..e4357b8060 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -169,6 +169,9 @@ pub const Value = opaque { pub const constNot = LLVMConstNot; extern fn LLVMConstNot(ConstantVal: *const Value) *const Value; + pub const constAdd = LLVMConstAdd; + extern fn LLVMConstAdd(LHSConstant: *const Value, RHSConstant: *const Value) *const Value; + pub const setWeak = LLVMSetWeak; extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void; diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 52083a492d..2dea485bf5 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -436,3 +436,25 @@ test "load pointer from packed struct" { try expect(i == 123); } } + +test "@ptrToInt on a packed struct field" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const S = struct { + const P = packed struct { + x: u8, + y: u8, + z: u32, + }; + var p0: P = P{ + .x = 1, + .y = 2, + .z = 0, + }; + }; + try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2); +}