| ... | @@ -1021,9 +1021,10 @@ pub const DeclGen = struct { | ... | @@ -1021,9 +1021,10 @@ pub const DeclGen = struct { |
| 1021 | } | 1021 | } |
| 1022 | | 1022 | |
| 1023 | /// This function generates a load for a constant in direct (ie, non-memory) representation. | 1023 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| 1024 | /// When the constant is simple, it can be generated directly using OpConstant instructions. When | 1024 | /// When the constant is simple, it can be generated directly using OpConstant instructions. |
| 1025 | /// the constant is more complicated however, it needs to be lowered to an indirect constant, which | 1025 | /// When the constant is more complicated however, it needs to be constructed using multiple values. This |
| 1026 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. | 1026 | /// is done by emitting a sequence of instructions that initialize the value. |
| | 1027 | // |
| 1027 | /// This function should only be called during function code generation. | 1028 | /// This function should only be called during function code generation. |
| 1028 | fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef { | 1029 | fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef { |
| 1029 | const mod = self.module; | 1030 | const mod = self.module; |
| ... | @@ -1037,7 +1038,7 @@ pub const DeclGen = struct { | ... | @@ -1037,7 +1038,7 @@ pub const DeclGen = struct { |
| 1037 | } | 1038 | } |
| 1038 | | 1039 | |
| 1039 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); | 1040 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); |
| 1040 | if (val.isUndef(mod)) { | 1041 | if (val.isUndefDeep(mod)) { |
| 1041 | return self.spv.constUndef(result_ty_ref); | 1042 | return self.spv.constUndef(result_ty_ref); |
| 1042 | } | 1043 | } |
| 1043 | | 1044 | |
| ... | @@ -1060,8 +1061,7 @@ pub const DeclGen = struct { | ... | @@ -1060,8 +1061,7 @@ pub const DeclGen = struct { |
| 1060 | .inferred_error_set_type, | 1061 | .inferred_error_set_type, |
| 1061 | => unreachable, // types, not values | 1062 | => unreachable, // types, not values |
| 1062 | | 1063 | |
| 1063 | .undef => unreachable, // handled above | 1064 | .undef, .runtime_value => unreachable, // handled above |
| 1064 | .runtime_value => unreachable, // ??? | | |
| 1065 | | 1065 | |
| 1066 | .variable, | 1066 | .variable, |
| 1067 | .extern_func, | 1067 | .extern_func, |
| ... | @@ -1103,6 +1103,49 @@ pub const DeclGen = struct { | ... | @@ -1103,6 +1103,49 @@ pub const DeclGen = struct { |
| 1103 | const value = try mod.getErrorValue(err.name); | 1103 | const value = try mod.getErrorValue(err.name); |
| 1104 | return try self.spv.constInt(result_ty_ref, value); | 1104 | return try self.spv.constInt(result_ty_ref, value); |
| 1105 | }, | 1105 | }, |
| | 1106 | .error_union => |error_union| { |
| | 1107 | // TODO: Error unions may be constructed with constant instructions if the payload type |
| | 1108 | // allows it. For now, just generate it here regardless. |
| | 1109 | const err_ty = switch (error_union.val) { |
| | 1110 | .err_name => ty.errorUnionSet(mod), |
| | 1111 | .payload => Type.err_int, |
| | 1112 | }; |
| | 1113 | const err_val = switch (error_union.val) { |
| | 1114 | .err_name => |err_name| (try mod.intern(.{ .err = .{ |
| | 1115 | .ty = ty.errorUnionSet(mod).toIntern(), |
| | 1116 | .name = err_name, |
| | 1117 | } })).toValue(), |
| | 1118 | .payload => try mod.intValue(Type.err_int, 0), |
| | 1119 | }; |
| | 1120 | const payload_ty = ty.errorUnionPayload(mod); |
| | 1121 | const eu_layout = self.errorUnionLayout(payload_ty); |
| | 1122 | if (!eu_layout.payload_has_bits) { |
| | 1123 | // We use the error type directly as the type. |
| | 1124 | return try self.constant(err_ty, err_val, .indirect); |
| | 1125 | } |
| | 1126 | |
| | 1127 | const payload_val = switch (error_union.val) { |
| | 1128 | .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), |
| | 1129 | .payload => |payload| payload, |
| | 1130 | }.toValue(); |
| | 1131 | |
| | 1132 | var constituents: [2]IdRef = undefined; |
| | 1133 | if (eu_layout.error_first) { |
| | 1134 | constituents[0] = try self.constant(err_ty, err_val, .indirect); |
| | 1135 | constituents[1] = try self.constant(payload_ty, payload_val, .indirect); |
| | 1136 | } else { |
| | 1137 | constituents[0] = try self.constant(payload_ty, payload_val, .indirect); |
| | 1138 | constituents[1] = try self.constant(err_ty, err_val, .indirect); |
| | 1139 | } |
| | 1140 | |
| | 1141 | const result_id = self.spv.allocId(); |
| | 1142 | try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ |
| | 1143 | .id_result_type = self.typeId(result_ty_ref), |
| | 1144 | .id_result = result_id, |
| | 1145 | .constituents = &constituents, |
| | 1146 | }); |
| | 1147 | return result_id; |
| | 1148 | }, |
| 1106 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra | 1149 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1107 | // OpVariable that is not really required. | 1150 | // OpVariable that is not really required. |
| 1108 | else => { | 1151 | else => { |
| ... | @@ -1316,7 +1359,6 @@ pub const DeclGen = struct { | ... | @@ -1316,7 +1359,6 @@ pub const DeclGen = struct { |
| 1316 | const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); | 1359 | const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); |
| 1317 | if (entry.found_existing) return entry.value_ptr.ty_ref; | 1360 | if (entry.found_existing) return entry.value_ptr.ty_ref; |
| 1318 | | 1361 | |
| 1319 | const ip = &mod.intern_pool; | | |
| 1320 | const fn_info = mod.typeToFunc(ty).?; | 1362 | const fn_info = mod.typeToFunc(ty).?; |
| 1321 | // TODO: Put this somewhere in Sema.zig | 1363 | // TODO: Put this somewhere in Sema.zig |
| 1322 | if (fn_info.is_var_args) | 1364 | if (fn_info.is_var_args) |