diff options
| author | Veikka Tuominen <git@vexu.eu> | 2023-09-26 11:16:03 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-26 11:16:03 +0300 |
| commit | f4c884617f499b52eaecc0ef674609c774052f8f (patch) | |
| tree | c24e4628c314d5e815f4b9796d0ff70335fa58a3 /src/codegen | |
| parent | 2adb932ad6ee4ff3d3c640cb8fb7bf7db0ff5d74 (diff) | |
| parent | 9f4649b197b720dbc168ced25eee0805d3b678b1 (diff) | |
| download | zig-f4c884617f499b52eaecc0ef674609c774052f8f.tar.gz zig-f4c884617f499b52eaecc0ef674609c774052f8f.zip | |
Merge pull request #17215 from kcbanner/read_from_memory_union
sema: add support for unions in readFromMemory and writeToMemory
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm.zig | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index dc2e2f3859..bfbcac1e73 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4108,25 +4108,28 @@ pub const Object = struct { if (layout.payload_size == 0) return o.lowerValue(un.tag); const union_obj = mod.typeToUnion(ty).?; - const field_index = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?; - - const field_ty = union_obj.field_types.get(ip)[field_index].toType(); - if (union_obj.getLayout(ip) == .Packed) { - if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0); - const small_int_val = try o.builder.castConst( - if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, - try o.lowerValue(un.val), - try o.builder.intType(@intCast(field_ty.bitSize(mod))), - ); - return o.builder.convConst(.unsigned, small_int_val, union_ty); - } + const container_layout = union_obj.getLayout(ip); + + var need_unnamed = false; + const payload = if (un.tag != .none) p: { + const field_index = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?; + const field_ty = union_obj.field_types.get(ip)[field_index].toType(); + if (container_layout == .Packed) { + if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0); + const small_int_val = try o.builder.castConst( + if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, + try o.lowerValue(un.val), + try o.builder.intType(@intCast(field_ty.bitSize(mod))), + ); + return o.builder.convConst(.unsigned, small_int_val, union_ty); + } + + // Sometimes we must make an unnamed struct because LLVM does + // not support bitcasting our payload struct to the true union payload type. + // Instead we use an unnamed struct and every reference to the global + // must pointer cast to the expected type before accessing the union. + need_unnamed = layout.most_aligned_field != field_index; - // Sometimes we must make an unnamed struct because LLVM does - // not support bitcasting our payload struct to the true union payload type. - // Instead we use an unnamed struct and every reference to the global - // must pointer cast to the expected type before accessing the union. - var need_unnamed = layout.most_aligned_field != field_index; - const payload = p: { if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { const padding_len = layout.payload_size; break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8)); @@ -4144,9 +4147,23 @@ pub const Object = struct { try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }), &.{ payload, try o.builder.undefConst(padding_ty) }, ); + } else p: { + assert(layout.tag_size == 0); + const union_val = try o.lowerValue(un.val); + if (container_layout == .Packed) { + const bitcast_val = try o.builder.castConst( + .bitcast, + union_val, + try o.builder.intType(@intCast(ty.bitSize(mod))), + ); + return o.builder.convConst(.unsigned, bitcast_val, union_ty); + } + + need_unnamed = true; + break :p union_val; }; - const payload_ty = payload.typeOf(&o.builder); + const payload_ty = payload.typeOf(&o.builder); if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed) try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty}) else |
