| ... | ... | @@ -537,6 +537,12 @@ pub const DeclGen = struct { |
| 537 | 537 | |
| 538 | 538 | fn addInt(self: *@This(), ty: Type, val: Value) !void { |
| 539 | 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 | 546 | const int_info = ty.intInfo(mod); |
| 541 | 547 | const int_bits = switch (int_info.signedness) { |
| 542 | 548 | .signed => @as(u64, @bitCast(val.toSignedInt(mod))), |
| ... | ... | @@ -544,7 +550,6 @@ pub const DeclGen = struct { |
| 544 | 550 | }; |
| 545 | 551 | |
| 546 | 552 | // TODO: Swap endianess if the compiler is big endian. |
| 547 | | const len = ty.abiSize(mod); |
| 548 | 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 | 672 | try self.addConstInt(u16, @as(u16, @intCast(int))); |
| 668 | 673 | }, |
| 669 | 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 | 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 | 687 | const eu_layout = dg.errorUnionLayout(payload_ty); |
| 675 | 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 | 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 | 696 | const ty_size = ty.abiSize(mod); |
| 682 | 697 | const padding = ty_size - payload_size - error_size; |
| 683 | 698 | |
| 684 | 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 | 701 | .payload => |payload| payload, |
| 687 | 702 | }.toValue(); |
| 688 | 703 | |
| 689 | 704 | if (eu_layout.error_first) { |
| 690 | | try self.lower(Type.anyerror, error_val); |
| 705 | try self.lower(err_ty, err_val); |
| 691 | 706 | try self.lower(payload_ty, payload_val); |
| 692 | 707 | } else { |
| 693 | 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 | 712 | try self.addUndef(padding); |
| ... | ... | @@ -705,9 +720,14 @@ pub const DeclGen = struct { |
| 705 | 720 | }, |
| 706 | 721 | .float => try self.addFloat(ty, val), |
| 707 | 722 | .ptr => |ptr| { |
| 723 | const ptr_ty = switch (ptr.len) { |
| 724 | .none => ty, |
| 725 | else => ty.slicePtrFieldType(mod), |
| 726 | }; |
| 708 | 727 | switch (ptr.addr) { |
| 709 | | .decl => |decl| try self.addDeclRef(ty, decl), |
| 710 | | .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl), |
| 728 | .decl => |decl| try self.addDeclRef(ptr_ty, 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 | 731 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), |
| 712 | 732 | } |
| 713 | 733 | if (ptr.len != .none) { |
| ... | ... | @@ -979,38 +999,84 @@ pub const DeclGen = struct { |
| 979 | 999 | /// the constant is more complicated however, it needs to be lowered to an indirect constant, which |
| 980 | 1000 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. |
| 981 | 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 | 1003 | const mod = self.module; |
| 984 | 1004 | const target = self.getTarget(); |
| 985 | 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 | 1014 | if (val.isUndef(mod)) { |
| 990 | 1015 | return self.spv.constUndef(result_ty_ref); |
| 991 | 1016 | } |
| 992 | 1017 | |
| 993 | | switch (ty.zigTypeTag(mod)) { |
| 994 | | .Int => { |
| 1018 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 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 | 1063 | if (ty.isSignedInt(mod)) { |
| 996 | 1064 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); |
| 997 | 1065 | } else { |
| 998 | 1066 | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); |
| 999 | 1067 | } |
| 1000 | 1068 | }, |
| 1001 | | .Bool => switch (repr) { |
| 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)) { |
| 1069 | .float => return switch (ty.floatBits(target)) { |
| 1006 | 1070 | 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }), |
| 1007 | 1071 | 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }), |
| 1008 | 1072 | 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }), |
| 1009 | 1073 | 80, 128 => unreachable, // TODO |
| 1010 | 1074 | else => unreachable, |
| 1011 | 1075 | }, |
| 1012 | | .ErrorSet => @panic("TODO"), |
| 1013 | | .ErrorUnion => @panic("TODO"), |
| 1076 | .err => |err| { |
| 1077 | const value = try mod.getErrorValue(err.name); |
| 1078 | return try self.spv.constInt(result_ty_ref, value); |
| 1079 | }, |
| 1014 | 1080 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1015 | 1081 | // OpVariable that is not really required. |
| 1016 | 1082 | else => { |
| ... | ... | @@ -1263,51 +1329,53 @@ pub const DeclGen = struct { |
| 1263 | 1329 | } }); |
| 1264 | 1330 | }, |
| 1265 | 1331 | .Struct => { |
| 1266 | | const struct_ty = mod.typeToStruct(ty).?; |
| 1267 | | const fields = struct_ty.fields.values(); |
| 1268 | | |
| 1269 | | if (ty.isSimpleTupleOrAnonStruct(mod)) { |
| 1270 | | const member_types = try self.gpa.alloc(CacheRef, fields.len); |
| 1271 | | defer self.gpa.free(member_types); |
| 1332 | const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 1333 | .anon_struct_type => |tuple| { |
| 1334 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); |
| 1335 | defer self.gpa.free(member_types); |
| 1272 | 1336 | |
| 1273 | | var member_index: usize = 0; |
| 1274 | | for (fields) |field| { |
| 1275 | | if (field.ty.ip_index != .unreachable_value or !field.ty.hasRuntimeBits(mod)) continue; |
| 1337 | var member_index: usize = 0; |
| 1338 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 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); |
| 1278 | | member_index += 1; |
| 1279 | | } |
| 1341 | member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect); |
| 1342 | member_index += 1; |
| 1343 | } |
| 1280 | 1344 | |
| 1281 | | return try self.spv.resolve(.{ .struct_type = .{ |
| 1282 | | .member_types = member_types[0..member_index], |
| 1283 | | } }); |
| 1284 | | } |
| 1345 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1346 | .member_types = member_types[0..member_index], |
| 1347 | } }); |
| 1348 | }, |
| 1349 | .struct_type => |struct_ty| struct_ty, |
| 1350 | else => unreachable, |
| 1351 | }; |
| 1285 | 1352 | |
| 1286 | | if (struct_ty.layout == .Packed) { |
| 1287 | | return try self.resolveType(struct_ty.backing_int_ty, .direct); |
| 1353 | const struct_obj = mod.structPtrUnwrap(struct_ty.index).?; |
| 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); |
| 1291 | | defer self.gpa.free(member_types); |
| 1292 | | |
| 1293 | | const member_names = try self.gpa.alloc(CacheString, fields.len); |
| 1294 | | defer self.gpa.free(member_names); |
| 1358 | var member_types = std.ArrayList(CacheRef).init(self.gpa); |
| 1359 | defer member_types.deinit(); |
| 1295 | 1360 | |
| 1296 | | var member_index: usize = 0; |
| 1297 | | for (fields, 0..) |field, i| { |
| 1298 | | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 1361 | var member_names = std.ArrayList(CacheString).init(self.gpa); |
| 1362 | defer member_names.deinit(); |
| 1299 | 1363 | |
| 1300 | | member_types[member_index] = try self.resolveType(field.ty, .indirect); |
| 1301 | | member_names[member_index] = try self.spv.resolveString(mod.intern_pool.stringToSlice(struct_ty.fields.keys()[i])); |
| 1302 | | member_index += 1; |
| 1364 | var it = struct_obj.runtimeFieldIterator(mod); |
| 1365 | while (it.next()) |field_and_index| { |
| 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 | 1375 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1308 | 1376 | .name = try self.spv.resolveString(name), |
| 1309 | | .member_types = member_types[0..member_index], |
| 1310 | | .member_names = member_names[0..member_index], |
| 1377 | .member_types = member_types.items, |
| 1378 | .member_names = member_names.items, |
| 1311 | 1379 | } }); |
| 1312 | 1380 | }, |
| 1313 | 1381 | .Optional => { |
| ... | ... | @@ -2512,9 +2580,9 @@ pub const DeclGen = struct { |
| 2512 | 2580 | // just an element. |
| 2513 | 2581 | var elem_ptr_info = ptr_ty.ptrInfo(mod); |
| 2514 | 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 | 2588 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |