diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-03-16 11:47:57 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-03-16 11:52:22 -0700 |
| commit | 1f313b3d7c757a8cdc5a52a1986f0f694b7ffc5f (patch) | |
| tree | 3a39c4523a700af4d2264e2eb3483f51bd010a25 | |
| parent | dd55b7294946cf1982815518422a007b19438d71 (diff) | |
| download | zig-1f313b3d7c757a8cdc5a52a1986f0f694b7ffc5f.tar.gz zig-1f313b3d7c757a8cdc5a52a1986f0f694b7ffc5f.zip | |
LLVM: make the load function copy isByRef=true types
| -rw-r--r-- | src/codegen/llvm.zig | 23 | ||||
| -rw-r--r-- | test/behavior/struct.zig | 26 |
2 files changed, 48 insertions, 1 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 9321b26e15..b09f4005cd 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -6767,6 +6767,9 @@ pub const FuncGen = struct { return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len); } + /// This function always performs a copy. For isByRef=true types, it creates a new + /// alloca and copies the value into it, then returns the alloca instruction. + /// For isByRef=false types, it creates a load instruction and returns it. fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value { const info = ptr_ty.ptrInfo().data; if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null; @@ -6775,7 +6778,25 @@ pub const FuncGen = struct { const ptr_alignment = ptr_ty.ptrAlignment(target); const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr()); if (info.host_size == 0) { - if (isByRef(info.pointee_type)) return ptr; + if (isByRef(info.pointee_type)) { + const elem_llvm_ty = try self.dg.llvmType(info.pointee_type); + const result_align = info.pointee_type.abiAlignment(target); + const max_align = @maximum(result_align, ptr_alignment); + const result_ptr = self.buildAlloca(elem_llvm_ty); + result_ptr.setAlignment(max_align); + const llvm_ptr_u8 = self.context.intType(8).pointerType(0); + const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits); + const size_bytes = info.pointee_type.abiSize(target); + _ = self.builder.buildMemCpy( + self.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""), + max_align, + self.builder.buildBitCast(ptr, llvm_ptr_u8, ""), + max_align, + llvm_usize.constInt(size_bytes, .False), + info.@"volatile", + ); + return result_ptr; + } const llvm_inst = self.builder.buildLoad(ptr, ""); llvm_inst.setAlignment(ptr_alignment); llvm_inst.setVolatile(ptr_volatile); diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 8383b81cd5..1d52900796 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -1290,3 +1290,29 @@ test "initialize struct with empty literal" { var s: S = .{}; try expect(s.x == 1234); } + +test "loading a struct pointer perfoms a copy" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const S = struct { + a: i32, + b: i32, + c: i32, + + fn swap(a: *@This(), b: *@This()) void { + const tmp = a.*; + a.* = b.*; + b.* = tmp; + } + }; + var s1: S = .{ .a = 1, .b = 2, .c = 3 }; + var s2: S = .{ .a = 4, .b = 5, .c = 6 }; + S.swap(&s1, &s2); + try expect(s1.a == 4); + try expect(s1.b == 5); + try expect(s1.c == 6); + try expect(s2.a == 1); + try expect(s2.b == 2); + try expect(s2.c == 3); +} |
