authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-27 14:21:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-27 14:22:47-07:00
log6d2ec7a4e39e3464bb5f14747937df9544e89ee7
tree2fe3eaaef62f7cc9fb3c52aec6d7acf707786281
parent052079c99455d01312d377d72fa1b8b5c0b22aad

LLVM: handle aggregate_init for packed structs


3 files changed, 57 insertions(+), 0 deletions(-)

src/codegen/llvm.zig+28
...@@ -6459,6 +6459,34 @@ pub const FuncGen = struct {...@@ -6459,6 +6459,34 @@ pub const FuncGen = struct {
6459 return vector;6459 return vector;
6460 },6460 },
6461 .Struct => {6461 .Struct => {
6462 if (result_ty.containerLayout() == .Packed) {
6463 const struct_obj = result_ty.castTag(.@"struct").?.data;
6464 const big_bits = struct_obj.packedIntegerBits(target);
6465 const int_llvm_ty = self.dg.context.intType(big_bits);
6466 const fields = struct_obj.fields.values();
6467 comptime assert(Type.packed_struct_layout_version == 2);
6468 var running_int: *const llvm.Value = int_llvm_ty.constNull();
6469 var running_bits: u16 = 0;
6470 for (elements) |elem, i| {
6471 const field = fields[i];
6472 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
6473
6474 const non_int_val = try self.resolveInst(elem);
6475 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
6476 const small_int_ty = self.dg.context.intType(ty_bit_size);
6477 const small_int_val = self.builder.buildBitCast(non_int_val, small_int_ty, "");
6478 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
6479 // If the field is as large as the entire packed struct, this
6480 // zext would go from, e.g. i16 to i16. This is legal with
6481 // constZExtOrBitCast but not legal with constZExt.
6482 const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
6483 const shifted = self.builder.buildShl(extended_int_val, shift_rhs, "");
6484 running_int = self.builder.buildOr(running_int, shifted, "");
6485 running_bits += ty_bit_size;
6486 }
6487 return running_int;
6488 }
6489
6462 var ptr_ty_buf: Type.Payload.Pointer = undefined;6490 var ptr_ty_buf: Type.Payload.Pointer = undefined;
64636491
6464 if (isByRef(result_ty)) {6492 if (isByRef(result_ty)) {
src/codegen/llvm/bindings.zig+8
...@@ -448,6 +448,14 @@ pub const Builder = opaque {...@@ -448,6 +448,14 @@ pub const Builder = opaque {
448 Name: [*:0]const u8,448 Name: [*:0]const u8,
449 ) *const Value;449 ) *const Value;
450450
451 pub const buildZExtOrBitCast = LLVMBuildZExtOrBitCast;
452 extern fn LLVMBuildZExtOrBitCast(
453 *const Builder,
454 Val: *const Value,
455 DestTy: *const Type,
456 Name: [*:0]const u8,
457 ) *const Value;
458
451 pub const buildSExt = LLVMBuildSExt;459 pub const buildSExt = LLVMBuildSExt;
452 extern fn LLVMBuildSExt(460 extern fn LLVMBuildSExt(
453 *const Builder,461 *const Builder,
test/behavior/struct.zig+21
...@@ -1294,3 +1294,24 @@ test "loading a struct pointer perfoms a copy" {...@@ -1294,3 +1294,24 @@ test "loading a struct pointer perfoms a copy" {
1294 try expect(s2.b == 2);1294 try expect(s2.b == 2);
1295 try expect(s2.c == 3);1295 try expect(s2.c == 3);
1296}1296}
1297
1298test "packed struct aggregate init" {
1299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1300 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1301 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1304
1305 const S = struct {
1306 fn foo(a: i2, b: i6) u8 {
1307 return @bitCast(u8, P{ .a = a, .b = b });
1308 }
1309
1310 const P = packed struct {
1311 a: i2,
1312 b: i6,
1313 };
1314 };
1315 const result = @bitCast(u8, S.foo(1, 2));
1316 try expect(result == 9);
1317}