Commit f880af369d

Andrew Kelley <andrew@ziglang.org>
2022-07-27 22:22:33
LLVM: fix lowering byte-aligned packed struct field pointers
1 parent dfc7493
Changed files (3)
src
test
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;
 
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;
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);
+}