authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-30 16:01:28+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-30 12:22:07-07:00
logc558de6655e2e9b72c5733b2d477ff18520d1c6b
tree279830f956fc27ba8f18e8959efc8a657c4fc0c8
parentd3b4b2edf140c002da4c9c1396c26e0f66835eb0

stage2 llvm: use tag value instead of field index in airUnionInit

Closes #12656

3 files changed, 50 insertions(+), 9 deletions(-)

src/Sema.zig+6-6
...@@ -21933,6 +21933,7 @@ fn unionFieldPtr(...@@ -21933,6 +21933,7 @@ fn unionFieldPtr(
21933 .mutable = union_ptr_ty.ptrIsMutable(),21933 .mutable = union_ptr_ty.ptrIsMutable(),
21934 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),21934 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
21935 });21935 });
21936 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
2193621937
21937 if (initializing and field.ty.zigTypeTag() == .NoReturn) {21938 if (initializing and field.ty.zigTypeTag() == .NoReturn) {
21938 const msg = msg: {21939 const msg = msg: {
...@@ -21954,11 +21955,10 @@ fn unionFieldPtr(...@@ -21954,11 +21955,10 @@ fn unionFieldPtr(
21954 if (union_val.isUndef()) {21955 if (union_val.isUndef()) {
21955 return sema.failWithUseOfUndef(block, src);21956 return sema.failWithUseOfUndef(block, src);
21956 }21957 }
21957 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
21958 const tag_and_val = union_val.castTag(.@"union").?.data;21958 const tag_and_val = union_val.castTag(.@"union").?.data;
21959 var field_tag_buf: Value.Payload.U32 = .{21959 var field_tag_buf: Value.Payload.U32 = .{
21960 .base = .{ .tag = .enum_field_index },21960 .base = .{ .tag = .enum_field_index },
21961 .data = @intCast(u32, enum_field_index),21961 .data = enum_field_index,
21962 };21962 };
21963 const field_tag = Value.initPayload(&field_tag_buf.base);21963 const field_tag = Value.initPayload(&field_tag_buf.base);
21964 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);21964 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
...@@ -21990,7 +21990,7 @@ fn unionFieldPtr(...@@ -21990,7 +21990,7 @@ fn unionFieldPtr(
21990 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and21990 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
21991 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)21991 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
21992 {21992 {
21993 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);21993 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
21994 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);21994 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
21995 // TODO would it be better if get_union_tag supported pointers to unions?21995 // TODO would it be better if get_union_tag supported pointers to unions?
21996 const union_val = try block.addTyOp(.load, union_ty, union_ptr);21996 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
...@@ -22020,15 +22020,15 @@ fn unionFieldVal(...@@ -22020,15 +22020,15 @@ fn unionFieldVal(
22020 const union_obj = union_ty.cast(Type.Payload.Union).?.data;22020 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
22021 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);22021 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
22022 const field = union_obj.fields.values()[field_index];22022 const field = union_obj.fields.values()[field_index];
22023 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
2202322024
22024 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {22025 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
22025 if (union_val.isUndef()) return sema.addConstUndef(field.ty);22026 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2202622027
22027 const tag_and_val = union_val.castTag(.@"union").?.data;22028 const tag_and_val = union_val.castTag(.@"union").?.data;
22028 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
22029 var field_tag_buf: Value.Payload.U32 = .{22029 var field_tag_buf: Value.Payload.U32 = .{
22030 .base = .{ .tag = .enum_field_index },22030 .base = .{ .tag = .enum_field_index },
22031 .data = @intCast(u32, enum_field_index),22031 .data = enum_field_index,
22032 };22032 };
22033 const field_tag = Value.initPayload(&field_tag_buf.base);22033 const field_tag = Value.initPayload(&field_tag_buf.base);
22034 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);22034 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
...@@ -22064,7 +22064,7 @@ fn unionFieldVal(...@@ -22064,7 +22064,7 @@ fn unionFieldVal(
22064 if (union_obj.layout == .Auto and block.wantSafety() and22064 if (union_obj.layout == .Auto and block.wantSafety() and
22065 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)22065 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
22066 {22066 {
22067 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);22067 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
22068 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);22068 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
22069 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);22069 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
22070 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);22070 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
src/codegen/llvm.zig+16-3
...@@ -8527,12 +8527,26 @@ pub const FuncGen = struct {...@@ -8527,12 +8527,26 @@ pub const FuncGen = struct {
8527 const union_llvm_ty = try self.dg.lowerType(union_ty);8527 const union_llvm_ty = try self.dg.lowerType(union_ty);
8528 const target = self.dg.module.getTarget();8528 const target = self.dg.module.getTarget();
8529 const layout = union_ty.unionGetLayout(target);8529 const layout = union_ty.unionGetLayout(target);
8530 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
8531 const tag_int = blk: {
8532 const tag_ty = union_ty.unionTagTypeHypothetical();
8533 const union_field_name = union_obj.fields.keys()[extra.field_index];
8534 const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;
8535 var tag_val_payload: Value.Payload.U32 = .{
8536 .base = .{ .tag = .enum_field_index },
8537 .data = @intCast(u32, enum_field_index),
8538 };
8539 const tag_val = Value.initPayload(&tag_val_payload.base);
8540 var int_payload: Value.Payload.U64 = undefined;
8541 const tag_int_val = tag_val.enumToInt(tag_ty, &int_payload);
8542 break :blk tag_int_val.toUnsignedInt(target);
8543 };
8530 if (layout.payload_size == 0) {8544 if (layout.payload_size == 0) {
8531 if (layout.tag_size == 0) {8545 if (layout.tag_size == 0) {
8532 return null;8546 return null;
8533 }8547 }
8534 assert(!isByRef(union_ty));8548 assert(!isByRef(union_ty));
8535 return union_llvm_ty.constInt(extra.field_index, .False);8549 return union_llvm_ty.constInt(tag_int, .False);
8536 }8550 }
8537 assert(isByRef(union_ty));8551 assert(isByRef(union_ty));
8538 // The llvm type of the alloca will the the named LLVM union type, which will not8552 // The llvm type of the alloca will the the named LLVM union type, which will not
...@@ -8541,7 +8555,6 @@ pub const FuncGen = struct {...@@ -8541,7 +8555,6 @@ pub const FuncGen = struct {
8541 // then set the fields appropriately.8555 // then set the fields appropriately.
8542 const result_ptr = self.buildAlloca(union_llvm_ty);8556 const result_ptr = self.buildAlloca(union_llvm_ty);
8543 const llvm_payload = try self.resolveInst(extra.init);8557 const llvm_payload = try self.resolveInst(extra.init);
8544 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
8545 assert(union_obj.haveFieldTypes());8558 assert(union_obj.haveFieldTypes());
8546 const field = union_obj.fields.values()[extra.field_index];8559 const field = union_obj.fields.values()[extra.field_index];
8547 const field_llvm_ty = try self.dg.lowerType(field.ty);8560 const field_llvm_ty = try self.dg.lowerType(field.ty);
...@@ -8625,7 +8638,7 @@ pub const FuncGen = struct {...@@ -8625,7 +8638,7 @@ pub const FuncGen = struct {
8625 };8638 };
8626 const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, "");8639 const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, "");
8627 const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty);8640 const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty);
8628 const llvm_tag = tag_llvm_ty.constInt(extra.field_index, .False);8641 const llvm_tag = tag_llvm_ty.constInt(tag_int, .False);
8629 const store_inst = self.builder.buildStore(llvm_tag, field_ptr);8642 const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
8630 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target));8643 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target));
8631 }8644 }
test/behavior/union.zig+28
...@@ -1324,3 +1324,31 @@ test "union and enum field order doesn't match" {...@@ -1324,3 +1324,31 @@ test "union and enum field order doesn't match" {
1324 x = .b;1324 x = .b;
1325 try expect(x == .b);1325 try expect(x == .b);
1326}1326}
1327
1328test "@unionInit uses tag value instead of field index" {
1329 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1330 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1331 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1333 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1334
1335 const E = enum(u8) {
1336 b = 255,
1337 a = 3,
1338 };
1339 const U = union(E) {
1340 a: usize,
1341 b: isize,
1342 };
1343 var i: isize = -1;
1344 var u = @unionInit(U, "b", i);
1345 {
1346 var a = u.b;
1347 try expect(a == i);
1348 }
1349 {
1350 var a = &u.b;
1351 try expect(a.* == i);
1352 }
1353 try expect(@enumToInt(u) == 255);
1354}