| ... | @@ -537,6 +537,12 @@ pub const DeclGen = struct { | ... | @@ -537,6 +537,12 @@ pub const DeclGen = struct { |
| 537 | | 537 | |
| 538 | fn addInt(self: *@This(), ty: Type, val: Value) !void { | 538 | fn addInt(self: *@This(), ty: Type, val: Value) !void { |
| 539 | const mod = self.dg.module; | 539 | const mod = self.dg.module; |
| | 540 | const len = ty.abiSize(mod); |
| | 541 | if (val.isUndef(mod)) { |
| | 542 | try self.addUndef(len); |
| | 543 | return; |
| | 544 | } |
| | 545 | |
| 540 | const int_info = ty.intInfo(mod); | 546 | const int_info = ty.intInfo(mod); |
| 541 | const int_bits = switch (int_info.signedness) { | 547 | const int_bits = switch (int_info.signedness) { |
| 542 | .signed => @as(u64, @bitCast(val.toSignedInt(mod))), | 548 | .signed => @as(u64, @bitCast(val.toSignedInt(mod))), |
| ... | @@ -544,7 +550,6 @@ pub const DeclGen = struct { | ... | @@ -544,7 +550,6 @@ pub const DeclGen = struct { |
| 544 | }; | 550 | }; |
| 545 | | 551 | |
| 546 | // TODO: Swap endianess if the compiler is big endian. | 552 | // TODO: Swap endianess if the compiler is big endian. |
| 547 | const len = ty.abiSize(mod); | | |
| 548 | try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]); | 553 | try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]); |
| 549 | } | 554 | } |
| 550 | | 555 | |
| ... | @@ -667,31 +672,41 @@ pub const DeclGen = struct { | ... | @@ -667,31 +672,41 @@ pub const DeclGen = struct { |
| 667 | try self.addConstInt(u16, @as(u16, @intCast(int))); | 672 | try self.addConstInt(u16, @as(u16, @intCast(int))); |
| 668 | }, | 673 | }, |
| 669 | .error_union => |error_union| { | 674 | .error_union => |error_union| { |
| | 675 | const err_ty = switch (error_union.val) { |
| | 676 | .err_name => ty.errorUnionSet(mod), |
| | 677 | .payload => Type.err_int, |
| | 678 | }; |
| | 679 | const err_val = switch (error_union.val) { |
| | 680 | .err_name => |err_name| (try mod.intern(.{ .err = .{ |
| | 681 | .ty = ty.errorUnionSet(mod).toIntern(), |
| | 682 | .name = err_name, |
| | 683 | } })).toValue(), |
| | 684 | .payload => try mod.intValue(Type.err_int, 0), |
| | 685 | }; |
| 670 | const payload_ty = ty.errorUnionPayload(mod); | 686 | const payload_ty = ty.errorUnionPayload(mod); |
| 671 | const is_pl = val.errorUnionIsPayload(mod); | | |
| 672 | const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0); | | |
| 673 | | | |
| 674 | const eu_layout = dg.errorUnionLayout(payload_ty); | 687 | const eu_layout = dg.errorUnionLayout(payload_ty); |
| 675 | if (!eu_layout.payload_has_bits) { | 688 | if (!eu_layout.payload_has_bits) { |
| 676 | return try self.lower(Type.anyerror, error_val); | 689 | // We use the error type directly as the type. |
| | 690 | try self.lower(err_ty, err_val); |
| | 691 | return; |
| 677 | } | 692 | } |
| 678 | | 693 | |
| 679 | const payload_size = payload_ty.abiSize(mod); | 694 | const payload_size = payload_ty.abiSize(mod); |
| 680 | const error_size = Type.anyerror.abiAlignment(mod); | 695 | const error_size = err_ty.abiSize(mod); |
| 681 | const ty_size = ty.abiSize(mod); | 696 | const ty_size = ty.abiSize(mod); |
| 682 | const padding = ty_size - payload_size - error_size; | 697 | const padding = ty_size - payload_size - error_size; |
| 683 | | 698 | |
| 684 | const payload_val = switch (error_union.val) { | 699 | const payload_val = switch (error_union.val) { |
| 685 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), | 700 | .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), |
| 686 | .payload => |payload| payload, | 701 | .payload => |payload| payload, |
| 687 | }.toValue(); | 702 | }.toValue(); |
| 688 | | 703 | |
| 689 | if (eu_layout.error_first) { | 704 | if (eu_layout.error_first) { |
| 690 | try self.lower(Type.anyerror, error_val); | 705 | try self.lower(err_ty, err_val); |
| 691 | try self.lower(payload_ty, payload_val); | 706 | try self.lower(payload_ty, payload_val); |
| 692 | } else { | 707 | } else { |
| 693 | try self.lower(payload_ty, payload_val); | 708 | try self.lower(payload_ty, payload_val); |
| 694 | try self.lower(Type.anyerror, error_val); | 709 | try self.lower(err_ty, err_val); |
| 695 | } | 710 | } |
| 696 | | 711 | |
| 697 | try self.addUndef(padding); | 712 | try self.addUndef(padding); |
| ... | @@ -705,9 +720,14 @@ pub const DeclGen = struct { | ... | @@ -705,9 +720,14 @@ pub const DeclGen = struct { |
| 705 | }, | 720 | }, |
| 706 | .float => try self.addFloat(ty, val), | 721 | .float => try self.addFloat(ty, val), |
| 707 | .ptr => |ptr| { | 722 | .ptr => |ptr| { |
| | 723 | const ptr_ty = switch (ptr.len) { |
| | 724 | .none => ty, |
| | 725 | else => ty.slicePtrFieldType(mod), |
| | 726 | }; |
| 708 | switch (ptr.addr) { | 727 | switch (ptr.addr) { |
| 709 | .decl => |decl| try self.addDeclRef(ty, decl), | 728 | .decl => |decl| try self.addDeclRef(ptr_ty, decl), |
| 710 | .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl), | 729 | .mut_decl => |mut_decl| try self.addDeclRef(ptr_ty, mut_decl.decl), |
| | 730 | .int => |int| try self.addInt(Type.usize, int.toValue()), |
| 711 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | 731 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), |
| 712 | } | 732 | } |
| 713 | if (ptr.len != .none) { | 733 | if (ptr.len != .none) { |
| ... | @@ -979,38 +999,84 @@ pub const DeclGen = struct { | ... | @@ -979,38 +999,84 @@ pub const DeclGen = struct { |
| 979 | /// the constant is more complicated however, it needs to be lowered to an indirect constant, which | 999 | /// the constant is more complicated however, it needs to be lowered to an indirect constant, which |
| 980 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. | 1000 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. |
| 981 | /// This function should only be called during function code generation. | 1001 | /// This function should only be called during function code generation. |
| 982 | fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef { | 1002 | fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef { |
| 983 | const mod = self.module; | 1003 | const mod = self.module; |
| 984 | const target = self.getTarget(); | 1004 | const target = self.getTarget(); |
| 985 | const result_ty_ref = try self.resolveType(ty, repr); | 1005 | const result_ty_ref = try self.resolveType(ty, repr); |
| 986 | | 1006 | |
| 987 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); | 1007 | var val = arg_val; |
| | 1008 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| | 1009 | .runtime_value => |rt| val = rt.val.toValue(), |
| | 1010 | else => {}, |
| | 1011 | } |
| 988 | | 1012 | |
| | 1013 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); |
| 989 | if (val.isUndef(mod)) { | 1014 | if (val.isUndef(mod)) { |
| 990 | return self.spv.constUndef(result_ty_ref); | 1015 | return self.spv.constUndef(result_ty_ref); |
| 991 | } | 1016 | } |
| 992 | | 1017 | |
| 993 | switch (ty.zigTypeTag(mod)) { | 1018 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 994 | .Int => { | 1019 | .int_type, |
| | 1020 | .ptr_type, |
| | 1021 | .array_type, |
| | 1022 | .vector_type, |
| | 1023 | .opt_type, |
| | 1024 | .anyframe_type, |
| | 1025 | .error_union_type, |
| | 1026 | .simple_type, |
| | 1027 | .struct_type, |
| | 1028 | .anon_struct_type, |
| | 1029 | .union_type, |
| | 1030 | .opaque_type, |
| | 1031 | .enum_type, |
| | 1032 | .func_type, |
| | 1033 | .error_set_type, |
| | 1034 | .inferred_error_set_type, |
| | 1035 | => unreachable, // types, not values |
| | 1036 | |
| | 1037 | .undef => unreachable, // handled above |
| | 1038 | .runtime_value => unreachable, // ??? |
| | 1039 | |
| | 1040 | .variable, |
| | 1041 | .extern_func, |
| | 1042 | .func, |
| | 1043 | .enum_literal, |
| | 1044 | .empty_enum_value, |
| | 1045 | => unreachable, // non-runtime values |
| | 1046 | |
| | 1047 | .simple_value => |simple_value| switch (simple_value) { |
| | 1048 | .undefined, |
| | 1049 | .void, |
| | 1050 | .null, |
| | 1051 | .empty_struct, |
| | 1052 | .@"unreachable", |
| | 1053 | .generic_poison, |
| | 1054 | => unreachable, // non-runtime values |
| | 1055 | |
| | 1056 | .false, .true => switch (repr) { |
| | 1057 | .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), |
| | 1058 | .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())), |
| | 1059 | }, |
| | 1060 | }, |
| | 1061 | |
| | 1062 | .int => { |
| 995 | if (ty.isSignedInt(mod)) { | 1063 | if (ty.isSignedInt(mod)) { |
| 996 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); | 1064 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); |
| 997 | } else { | 1065 | } else { |
| 998 | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); | 1066 | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); |
| 999 | } | 1067 | } |
| 1000 | }, | 1068 | }, |
| 1001 | .Bool => switch (repr) { | 1069 | .float => return switch (ty.floatBits(target)) { |
| 1002 | .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), | | |
| 1003 | .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())), | | |
| 1004 | }, | | |
| 1005 | .Float => return switch (ty.floatBits(target)) { | | |
| 1006 | 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }), | 1070 | 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }), |
| 1007 | 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }), | 1071 | 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }), |
| 1008 | 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }), | 1072 | 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }), |
| 1009 | 80, 128 => unreachable, // TODO | 1073 | 80, 128 => unreachable, // TODO |
| 1010 | else => unreachable, | 1074 | else => unreachable, |
| 1011 | }, | 1075 | }, |
| 1012 | .ErrorSet => @panic("TODO"), | 1076 | .err => |err| { |
| 1013 | .ErrorUnion => @panic("TODO"), | 1077 | const value = try mod.getErrorValue(err.name); |
| | 1078 | return try self.spv.constInt(result_ty_ref, value); |
| | 1079 | }, |
| 1014 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra | 1080 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1015 | // OpVariable that is not really required. | 1081 | // OpVariable that is not really required. |
| 1016 | else => { | 1082 | else => { |
| ... | @@ -1263,51 +1329,53 @@ pub const DeclGen = struct { | ... | @@ -1263,51 +1329,53 @@ pub const DeclGen = struct { |
| 1263 | } }); | 1329 | } }); |
| 1264 | }, | 1330 | }, |
| 1265 | .Struct => { | 1331 | .Struct => { |
| 1266 | const struct_ty = mod.typeToStruct(ty).?; | 1332 | const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 1267 | const fields = struct_ty.fields.values(); | 1333 | .anon_struct_type => |tuple| { |
| 1268 | | 1334 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); |
| 1269 | if (ty.isSimpleTupleOrAnonStruct(mod)) { | 1335 | defer self.gpa.free(member_types); |
| 1270 | const member_types = try self.gpa.alloc(CacheRef, fields.len); | | |
| 1271 | defer self.gpa.free(member_types); | | |
| 1272 | | 1336 | |
| 1273 | var member_index: usize = 0; | 1337 | var member_index: usize = 0; |
| 1274 | for (fields) |field| { | 1338 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 1275 | if (field.ty.ip_index != .unreachable_value or !field.ty.hasRuntimeBits(mod)) continue; | 1339 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 1276 | | 1340 | |
| 1277 | member_types[member_index] = try self.resolveType(field.ty, .indirect); | 1341 | member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect); |
| 1278 | member_index += 1; | 1342 | member_index += 1; |
| 1279 | } | 1343 | } |
| 1280 | | 1344 | |
| 1281 | return try self.spv.resolve(.{ .struct_type = .{ | 1345 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1282 | .member_types = member_types[0..member_index], | 1346 | .member_types = member_types[0..member_index], |
| 1283 | } }); | 1347 | } }); |
| 1284 | } | 1348 | }, |
| | 1349 | .struct_type => |struct_ty| struct_ty, |
| | 1350 | else => unreachable, |
| | 1351 | }; |
| 1285 | | 1352 | |
| 1286 | if (struct_ty.layout == .Packed) { | 1353 | const struct_obj = mod.structPtrUnwrap(struct_ty.index).?; |
| 1287 | return try self.resolveType(struct_ty.backing_int_ty, .direct); | 1354 | if (struct_obj.layout == .Packed) { |
| | 1355 | return try self.resolveType(struct_obj.backing_int_ty, .direct); |
| 1288 | } | 1356 | } |
| 1289 | | 1357 | |
| 1290 | const member_types = try self.gpa.alloc(CacheRef, fields.len); | 1358 | var member_types = std.ArrayList(CacheRef).init(self.gpa); |
| 1291 | defer self.gpa.free(member_types); | 1359 | defer member_types.deinit(); |
| 1292 | | | |
| 1293 | const member_names = try self.gpa.alloc(CacheString, fields.len); | | |
| 1294 | defer self.gpa.free(member_names); | | |
| 1295 | | 1360 | |
| 1296 | var member_index: usize = 0; | 1361 | var member_names = std.ArrayList(CacheString).init(self.gpa); |
| 1297 | for (fields, 0..) |field, i| { | 1362 | defer member_names.deinit(); |
| 1298 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | | |
| 1299 | | 1363 | |
| 1300 | member_types[member_index] = try self.resolveType(field.ty, .indirect); | 1364 | var it = struct_obj.runtimeFieldIterator(mod); |
| 1301 | member_names[member_index] = try self.spv.resolveString(mod.intern_pool.stringToSlice(struct_ty.fields.keys()[i])); | 1365 | while (it.next()) |field_and_index| { |
| 1302 | member_index += 1; | 1366 | const field = field_and_index.field; |
| | 1367 | const index = field_and_index.index; |
| | 1368 | const field_name = mod.intern_pool.stringToSlice(struct_obj.fields.keys()[index]); |
| | 1369 | try member_types.append(try self.resolveType(field.ty, .indirect)); |
| | 1370 | try member_names.append(try self.spv.resolveString(field_name)); |
| 1303 | } | 1371 | } |
| 1304 | | 1372 | |
| 1305 | const name = mod.intern_pool.stringToSlice(try struct_ty.getFullyQualifiedName(self.module)); | 1373 | const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); |
| 1306 | | 1374 | |
| 1307 | return try self.spv.resolve(.{ .struct_type = .{ | 1375 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1308 | .name = try self.spv.resolveString(name), | 1376 | .name = try self.spv.resolveString(name), |
| 1309 | .member_types = member_types[0..member_index], | 1377 | .member_types = member_types.items, |
| 1310 | .member_names = member_names[0..member_index], | 1378 | .member_names = member_names.items, |
| 1311 | } }); | 1379 | } }); |
| 1312 | }, | 1380 | }, |
| 1313 | .Optional => { | 1381 | .Optional => { |
| ... | @@ -2512,9 +2580,9 @@ pub const DeclGen = struct { | ... | @@ -2512,9 +2580,9 @@ pub const DeclGen = struct { |
| 2512 | // just an element. | 2580 | // just an element. |
| 2513 | var elem_ptr_info = ptr_ty.ptrInfo(mod); | 2581 | var elem_ptr_info = ptr_ty.ptrInfo(mod); |
| 2514 | elem_ptr_info.flags.size = .One; | 2582 | elem_ptr_info.flags.size = .One; |
| 2515 | const elem_ptr_ty = elem_ptr_info.child.toType(); | 2583 | const elem_ptr_ty = try mod.intern_pool.get(mod.gpa, .{ .ptr_type = elem_ptr_info }); |
| 2516 | | 2584 | |
| 2517 | return try self.load(elem_ptr_ty, elem_ptr_id); | 2585 | return try self.load(elem_ptr_ty.toType(), elem_ptr_id); |
| 2518 | } | 2586 | } |
| 2519 | | 2587 | |
| 2520 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2588 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |