authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-16 11:47:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-16 11:52:22-07:00
log1f313b3d7c757a8cdc5a52a1986f0f694b7ffc5f
tree3a39c4523a700af4d2264e2eb3483f51bd010a25
parentdd55b7294946cf1982815518422a007b19438d71

LLVM: make the load function copy isByRef=true types


2 files changed, 48 insertions(+), 1 deletions(-)

src/codegen/llvm.zig+22-1
......@@ -6767,6 +6767,9 @@ pub const FuncGen = struct {
67676767 return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);
67686768 }
67696769
6770 /// This function always performs a copy. For isByRef=true types, it creates a new
6771 /// alloca and copies the value into it, then returns the alloca instruction.
6772 /// For isByRef=false types, it creates a load instruction and returns it.
67706773 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
67716774 const info = ptr_ty.ptrInfo().data;
67726775 if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null;
......@@ -6775,7 +6778,25 @@ pub const FuncGen = struct {
67756778 const ptr_alignment = ptr_ty.ptrAlignment(target);
67766779 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
67776780 if (info.host_size == 0) {
6778 if (isByRef(info.pointee_type)) return ptr;
6781 if (isByRef(info.pointee_type)) {
6782 const elem_llvm_ty = try self.dg.llvmType(info.pointee_type);
6783 const result_align = info.pointee_type.abiAlignment(target);
6784 const max_align = @maximum(result_align, ptr_alignment);
6785 const result_ptr = self.buildAlloca(elem_llvm_ty);
6786 result_ptr.setAlignment(max_align);
6787 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
6788 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);
6789 const size_bytes = info.pointee_type.abiSize(target);
6790 _ = self.builder.buildMemCpy(
6791 self.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""),
6792 max_align,
6793 self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
6794 max_align,
6795 llvm_usize.constInt(size_bytes, .False),
6796 info.@"volatile",
6797 );
6798 return result_ptr;
6799 }
67796800 const llvm_inst = self.builder.buildLoad(ptr, "");
67806801 llvm_inst.setAlignment(ptr_alignment);
67816802 llvm_inst.setVolatile(ptr_volatile);
test/behavior/struct.zig+26
......@@ -1290,3 +1290,29 @@ test "initialize struct with empty literal" {
12901290 var s: S = .{};
12911291 try expect(s.x == 1234);
12921292}
1293
1294test "loading a struct pointer perfoms a copy" {
1295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1297
1298 const S = struct {
1299 a: i32,
1300 b: i32,
1301 c: i32,
1302
1303 fn swap(a: *@This(), b: *@This()) void {
1304 const tmp = a.*;
1305 a.* = b.*;
1306 b.* = tmp;
1307 }
1308 };
1309 var s1: S = .{ .a = 1, .b = 2, .c = 3 };
1310 var s2: S = .{ .a = 4, .b = 5, .c = 6 };
1311 S.swap(&s1, &s2);
1312 try expect(s1.a == 4);
1313 try expect(s1.b == 5);
1314 try expect(s1.c == 6);
1315 try expect(s2.a == 1);
1316 try expect(s2.b == 2);
1317 try expect(s2.c == 3);
1318}