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(
2193321933 .mutable = union_ptr_ty.ptrIsMutable(),
2193421934 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
2193521935 });
21936 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
2193621937
2193721938 if (initializing and field.ty.zigTypeTag() == .NoReturn) {
2193821939 const msg = msg: {
......@@ -21954,11 +21955,10 @@ fn unionFieldPtr(
2195421955 if (union_val.isUndef()) {
2195521956 return sema.failWithUseOfUndef(block, src);
2195621957 }
21957 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2195821958 const tag_and_val = union_val.castTag(.@"union").?.data;
2195921959 var field_tag_buf: Value.Payload.U32 = .{
2196021960 .base = .{ .tag = .enum_field_index },
21961 .data = @intCast(u32, enum_field_index),
21961 .data = enum_field_index,
2196221962 };
2196321963 const field_tag = Value.initPayload(&field_tag_buf.base);
2196421964 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
......@@ -21990,7 +21990,7 @@ fn unionFieldPtr(
2199021990 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
2199121991 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2199221992 {
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);
2199421994 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
2199521995 // TODO would it be better if get_union_tag supported pointers to unions?
2199621996 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
......@@ -22020,15 +22020,15 @@ fn unionFieldVal(
2202022020 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
2202122021 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2202222022 const field = union_obj.fields.values()[field_index];
22023 const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
2202322024
2202422025 if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| {
2202522026 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2202622027
2202722028 const tag_and_val = union_val.castTag(.@"union").?.data;
22028 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2202922029 var field_tag_buf: Value.Payload.U32 = .{
2203022030 .base = .{ .tag = .enum_field_index },
22031 .data = @intCast(u32, enum_field_index),
22031 .data = enum_field_index,
2203222032 };
2203322033 const field_tag = Value.initPayload(&field_tag_buf.base);
2203422034 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
......@@ -22064,7 +22064,7 @@ fn unionFieldVal(
2206422064 if (union_obj.layout == .Auto and block.wantSafety() and
2206522065 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2206622066 {
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);
2206822068 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
2206922069 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
2207022070 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 {
85278527 const union_llvm_ty = try self.dg.lowerType(union_ty);
85288528 const target = self.dg.module.getTarget();
85298529 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 };
85308544 if (layout.payload_size == 0) {
85318545 if (layout.tag_size == 0) {
85328546 return null;
85338547 }
85348548 assert(!isByRef(union_ty));
8535 return union_llvm_ty.constInt(extra.field_index, .False);
8549 return union_llvm_ty.constInt(tag_int, .False);
85368550 }
85378551 assert(isByRef(union_ty));
85388552 // The llvm type of the alloca will the the named LLVM union type, which will not
......@@ -8541,7 +8555,6 @@ pub const FuncGen = struct {
85418555 // then set the fields appropriately.
85428556 const result_ptr = self.buildAlloca(union_llvm_ty);
85438557 const llvm_payload = try self.resolveInst(extra.init);
8544 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
85458558 assert(union_obj.haveFieldTypes());
85468559 const field = union_obj.fields.values()[extra.field_index];
85478560 const field_llvm_ty = try self.dg.lowerType(field.ty);
......@@ -8625,7 +8638,7 @@ pub const FuncGen = struct {
86258638 };
86268639 const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, "");
86278640 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);
86298642 const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
86308643 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target));
86318644 }
test/behavior/union.zig+28
......@@ -1324,3 +1324,31 @@ test "union and enum field order doesn't match" {
13241324 x = .b;
13251325 try expect(x == .b);
13261326}
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}