| ... | ... | @@ -242,7 +242,7 @@ pub const DeclGen = struct { |
| 242 | 242 | return self.spv.declPtr(spv_decl_index).result_id; |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | | return try self.constant(ty, val); |
| 245 | return try self.constant(ty, val, .direct); |
| 246 | 246 | } |
| 247 | 247 | const index = Air.refToIndex(inst).?; |
| 248 | 248 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. |
| ... | ... | @@ -1021,14 +1021,16 @@ pub const DeclGen = struct { |
| 1021 | 1021 | /// the constant is more complicated however, it needs to be lowered to an indirect constant, which |
| 1022 | 1022 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. |
| 1023 | 1023 | /// This function should only be called during function code generation. |
| 1024 | | fn constant(self: *DeclGen, ty: Type, val: Value) !IdRef { |
| 1024 | fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef { |
| 1025 | 1025 | const target = self.getTarget(); |
| 1026 | 1026 | const section = &self.spv.sections.types_globals_constants; |
| 1027 | | const result_ty_ref = try self.resolveType(ty, .direct); |
| 1027 | const result_ty_ref = try self.resolveType(ty, repr); |
| 1028 | 1028 | const result_ty_id = self.typeId(result_ty_ref); |
| 1029 | | const result_id = self.spv.allocId(); |
| 1029 | |
| 1030 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); |
| 1030 | 1031 | |
| 1031 | 1032 | if (val.isUndef()) { |
| 1033 | const result_id = self.spv.allocId(); |
| 1032 | 1034 | try section.emit(self.spv.gpa, .OpUndef, .{ |
| 1033 | 1035 | .id_result_type = result_ty_id, |
| 1034 | 1036 | .id_result = result_id, |
| ... | ... | @@ -1039,24 +1041,76 @@ pub const DeclGen = struct { |
| 1039 | 1041 | switch (ty.zigTypeTag()) { |
| 1040 | 1042 | .Int => { |
| 1041 | 1043 | if (ty.isSignedInt()) { |
| 1042 | | try self.genConstInt(result_ty_ref, result_id, val.toSignedInt(target)); |
| 1044 | return try self.constInt(result_ty_ref, val.toSignedInt(target)); |
| 1043 | 1045 | } else { |
| 1044 | | try self.genConstInt(result_ty_ref, result_id, val.toUnsignedInt(target)); |
| 1046 | return try self.constInt(result_ty_ref, val.toUnsignedInt(target)); |
| 1047 | } |
| 1048 | }, |
| 1049 | .Bool => switch (repr) { |
| 1050 | .direct => { |
| 1051 | const result_id = self.spv.allocId(); |
| 1052 | const operands = .{ .id_result_type = result_ty_id, .id_result = result_id }; |
| 1053 | if (val.toBool()) { |
| 1054 | try section.emit(self.spv.gpa, .OpConstantTrue, operands); |
| 1055 | } else { |
| 1056 | try section.emit(self.spv.gpa, .OpConstantFalse, operands); |
| 1057 | } |
| 1058 | return result_id; |
| 1059 | }, |
| 1060 | .indirect => return try self.constInt(result_ty_ref, @boolToInt(val.toBool())), |
| 1061 | }, |
| 1062 | .Float => { |
| 1063 | const result_id = self.spv.allocId(); |
| 1064 | switch (ty.floatBits(target)) { |
| 1065 | 16 => try self.spv.emitConstant(result_ty_id, result_id, .{ .float32 = val.toFloat(f16) }), |
| 1066 | 32 => try self.spv.emitConstant(result_ty_id, result_id, .{ .float32 = val.toFloat(f32) }), |
| 1067 | 64 => try self.spv.emitConstant(result_ty_id, result_id, .{ .float64 = val.toFloat(f64) }), |
| 1068 | 80, 128 => unreachable, // TODO |
| 1069 | else => unreachable, |
| 1045 | 1070 | } |
| 1071 | return result_id; |
| 1046 | 1072 | }, |
| 1047 | | .Bool => { |
| 1048 | | const operands = .{ .id_result_type = result_ty_id, .id_result = result_id }; |
| 1049 | | if (val.toBool()) { |
| 1050 | | try section.emit(self.spv.gpa, .OpConstantTrue, operands); |
| 1073 | .ErrorSet => { |
| 1074 | const value = switch (val.tag()) { |
| 1075 | .@"error" => blk: { |
| 1076 | const err_name = val.castTag(.@"error").?.data.name; |
| 1077 | const kv = try self.module.getErrorValue(err_name); |
| 1078 | break :blk @intCast(u16, kv.value); |
| 1079 | }, |
| 1080 | .zero => 0, |
| 1081 | else => unreachable, |
| 1082 | }; |
| 1083 | |
| 1084 | return try self.constInt(result_ty_ref, value); |
| 1085 | }, |
| 1086 | .ErrorUnion => { |
| 1087 | const payload_ty = ty.errorUnionPayload(); |
| 1088 | const is_pl = val.errorUnionIsPayload(); |
| 1089 | const error_val = if (!is_pl) val else Value.initTag(.zero); |
| 1090 | |
| 1091 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 1092 | if (!eu_layout.payload_has_bits) { |
| 1093 | return try self.constant(Type.anyerror, error_val, repr); |
| 1094 | } |
| 1095 | |
| 1096 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); |
| 1097 | |
| 1098 | var members: [2]IdRef = undefined; |
| 1099 | if (eu_layout.error_first) { |
| 1100 | members[0] = try self.constant(Type.anyerror, error_val, .indirect); |
| 1101 | members[1] = try self.constant(payload_ty, payload_val, .indirect); |
| 1051 | 1102 | } else { |
| 1052 | | try section.emit(self.spv.gpa, .OpConstantFalse, operands); |
| 1103 | members[0] = try self.constant(payload_ty, payload_val, .indirect); |
| 1104 | members[1] = try self.constant(Type.anyerror, error_val, .indirect); |
| 1053 | 1105 | } |
| 1106 | return try self.spv.constComposite(result_ty_ref, &members); |
| 1054 | 1107 | }, |
| 1055 | 1108 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1056 | 1109 | // OpVariable that is not really required. |
| 1057 | 1110 | else => { |
| 1058 | 1111 | // The value cannot be generated directly, so generate it as an indirect constant, |
| 1059 | 1112 | // and then perform an OpLoad. |
| 1113 | const result_id = self.spv.allocId(); |
| 1060 | 1114 | const alignment = ty.abiAlignment(target); |
| 1061 | 1115 | const spv_decl_index = try self.spv.allocDecl(.global); |
| 1062 | 1116 | |
| ... | ... | @@ -1078,10 +1132,9 @@ pub const DeclGen = struct { |
| 1078 | 1132 | }); |
| 1079 | 1133 | // TODO: Convert bools? This logic should hook into `load`. It should be a dead |
| 1080 | 1134 | // path though considering .Bool is handled above. |
| 1135 | return result_id; |
| 1081 | 1136 | }, |
| 1082 | 1137 | } |
| 1083 | | |
| 1084 | | return result_id; |
| 1085 | 1138 | } |
| 1086 | 1139 | |
| 1087 | 1140 | /// Turn a Zig type into a SPIR-V Type, and return its type result-id. |