| ... | @@ -429,9 +429,33 @@ pub const DeclGen = struct { | ... | @@ -429,9 +429,33 @@ pub const DeclGen = struct { |
| 429 | }, | 429 | }, |
| 430 | else => unreachable, // TODO | 430 | else => unreachable, // TODO |
| 431 | }, | 431 | }, |
| | 432 | .Enum => { |
| | 433 | var int_buffer: Value.Payload.U64 = undefined; |
| | 434 | const int_val = val.enumToInt(ty, &int_buffer).toUnsignedInt(target); |
| | 435 | |
| | 436 | var buffer: Type.Payload.Bits = undefined; |
| | 437 | const int_ty = ty.intTagType(&buffer); |
| | 438 | const int_info = int_ty.intInfo(target); |
| | 439 | |
| | 440 | const backing_bits = self.backingIntBits(int_info.bits) orelse { |
| | 441 | return self.todo("implement composite int constants for {}", .{int_ty.fmtDebug()}); |
| | 442 | }; |
| | 443 | |
| | 444 | const value: spec.LiteralContextDependentNumber = switch (backing_bits) { |
| | 445 | 1...32 => .{ .uint32 = @truncate(u32, int_val) }, |
| | 446 | 33...64 => .{ .uint64 = int_val }, |
| | 447 | else => unreachable, |
| | 448 | }; |
| | 449 | |
| | 450 | try section.emit(self.spv.gpa, .OpConstant, .{ |
| | 451 | .id_result_type = result_type_id, |
| | 452 | .id_result = result_id, |
| | 453 | .value = value, |
| | 454 | }); |
| | 455 | }, |
| 432 | .Void => unreachable, | 456 | .Void => unreachable, |
| 433 | .Fn => unreachable, | 457 | .Fn => unreachable, |
| 434 | else => return self.todo("constant generation of type {}", .{ty.fmtDebug()}), | 458 | else => return self.todo("constant generation of type {s}: {}", .{ @tagName(ty.zigTypeTag()), ty.fmtDebug() }), |
| 435 | } | 459 | } |
| 436 | | 460 | |
| 437 | return result_id.toRef(); | 461 | return result_id.toRef(); |
| ... | @@ -742,6 +766,8 @@ pub const DeclGen = struct { | ... | @@ -742,6 +766,8 @@ pub const DeclGen = struct { |
| 742 | .slice_elem_ptr => try self.airSliceElemPtr(inst), | 766 | .slice_elem_ptr => try self.airSliceElemPtr(inst), |
| 743 | .slice_elem_val => try self.airSliceElemVal(inst), | 767 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 744 | | 768 | |
| | 769 | .struct_field_val => try self.airStructFieldVal(inst), |
| | 770 | |
| 745 | .cmp_eq => try self.airCmp(inst, .OpFOrdEqual, .OpLogicalEqual, .OpIEqual), | 771 | .cmp_eq => try self.airCmp(inst, .OpFOrdEqual, .OpLogicalEqual, .OpIEqual), |
| 746 | .cmp_neq => try self.airCmp(inst, .OpFOrdNotEqual, .OpLogicalNotEqual, .OpINotEqual), | 772 | .cmp_neq => try self.airCmp(inst, .OpFOrdNotEqual, .OpLogicalNotEqual, .OpINotEqual), |
| 747 | .cmp_gt => try self.airCmp(inst, .OpFOrdGreaterThan, .OpSGreaterThan, .OpUGreaterThan), | 773 | .cmp_gt => try self.airCmp(inst, .OpFOrdGreaterThan, .OpSGreaterThan, .OpUGreaterThan), |
| ... | @@ -749,10 +775,12 @@ pub const DeclGen = struct { | ... | @@ -749,10 +775,12 @@ pub const DeclGen = struct { |
| 749 | .cmp_lt => try self.airCmp(inst, .OpFOrdLessThan, .OpSLessThan, .OpULessThan), | 775 | .cmp_lt => try self.airCmp(inst, .OpFOrdLessThan, .OpSLessThan, .OpULessThan), |
| 750 | .cmp_lte => try self.airCmp(inst, .OpFOrdLessThanEqual, .OpSLessThanEqual, .OpULessThanEqual), | 776 | .cmp_lte => try self.airCmp(inst, .OpFOrdLessThanEqual, .OpSLessThanEqual, .OpULessThanEqual), |
| 751 | | 777 | |
| 752 | .arg => self.airArg(), | 778 | .arg => self.airArg(), |
| 753 | .alloc => try self.airAlloc(inst), | 779 | .alloc => try self.airAlloc(inst), |
| 754 | .block => try self.airBlock(inst), | 780 | // TODO: We probably need to have a special implementation of this for the C abi. |
| 755 | .load => try self.airLoad(inst), | 781 | .ret_ptr => try self.airAlloc(inst), |
| | 782 | .block => try self.airBlock(inst), |
| | 783 | .load => try self.airLoad(inst), |
| 756 | | 784 | |
| 757 | .br => return self.airBr(inst), | 785 | .br => return self.airBr(inst), |
| 758 | .breakpoint => return, | 786 | .breakpoint => return, |
| ... | @@ -761,6 +789,7 @@ pub const DeclGen = struct { | ... | @@ -761,6 +789,7 @@ pub const DeclGen = struct { |
| 761 | .dbg_stmt => return self.airDbgStmt(inst), | 789 | .dbg_stmt => return self.airDbgStmt(inst), |
| 762 | .loop => return self.airLoop(inst), | 790 | .loop => return self.airLoop(inst), |
| 763 | .ret => return self.airRet(inst), | 791 | .ret => return self.airRet(inst), |
| | 792 | .ret_load => return self.airRetLoad(inst), |
| 764 | .store => return self.airStore(inst), | 793 | .store => return self.airStore(inst), |
| 765 | .unreach => return self.airUnreach(), | 794 | .unreach => return self.airUnreach(), |
| 766 | | 795 | |
| ... | @@ -989,12 +1018,12 @@ pub const DeclGen = struct { | ... | @@ -989,12 +1018,12 @@ pub const DeclGen = struct { |
| 989 | .composite_integer => { | 1018 | .composite_integer => { |
| 990 | return self.todo("binary operations for composite integers", .{}); | 1019 | return self.todo("binary operations for composite integers", .{}); |
| 991 | }, | 1020 | }, |
| 992 | .strange_integer => { | | |
| 993 | return self.todo("comparison for strange integers", .{}); | | |
| 994 | }, | | |
| 995 | .float => 0, | 1021 | .float => 0, |
| 996 | .bool => 1, | 1022 | .bool => 1, |
| 997 | .integer => switch (info.signedness) { | 1023 | // TODO: Should strange integers be masked before comparison? |
| | 1024 | .strange_integer, |
| | 1025 | .integer, |
| | 1026 | => switch (info.signedness) { |
| 998 | .signed => @as(usize, 1), | 1027 | .signed => @as(usize, 1), |
| 999 | .unsigned => @as(usize, 2), | 1028 | .unsigned => @as(usize, 2), |
| 1000 | }, | 1029 | }, |
| ... | @@ -1144,6 +1173,32 @@ pub const DeclGen = struct { | ... | @@ -1144,6 +1173,32 @@ pub const DeclGen = struct { |
| 1144 | return result_id.toRef(); | 1173 | return result_id.toRef(); |
| 1145 | } | 1174 | } |
| 1146 | | 1175 | |
| | 1176 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| | 1177 | if (self.liveness.isUnused(inst)) return null; |
| | 1178 | |
| | 1179 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 1180 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| | 1181 | |
| | 1182 | const struct_ty = self.air.typeOf(struct_field.struct_operand); |
| | 1183 | const object = try self.resolve(struct_field.struct_operand); |
| | 1184 | const field_index = struct_field.field_index; |
| | 1185 | const field_ty = struct_ty.structFieldType(field_index); |
| | 1186 | const field_ty_id = try self.resolveTypeId(field_ty); |
| | 1187 | |
| | 1188 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) return null; |
| | 1189 | |
| | 1190 | assert(struct_ty.zigTypeTag() == .Struct); // Cannot do unions yet. |
| | 1191 | |
| | 1192 | const result_id = self.spv.allocId(); |
| | 1193 | try self.func.body.emit(self.spv.gpa, .OpCompositeExtract, .{ |
| | 1194 | .id_result_type = field_ty_id, |
| | 1195 | .id_result = result_id, |
| | 1196 | .composite = object, |
| | 1197 | .indexes = &.{field_index}, |
| | 1198 | }); |
| | 1199 | return result_id.toRef(); |
| | 1200 | } |
| | 1201 | |
| 1147 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 1202 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 1148 | if (self.liveness.isUnused(inst)) return null; | 1203 | if (self.liveness.isUnused(inst)) return null; |
| 1149 | const ty = self.air.typeOfIndex(inst); | 1204 | const ty = self.air.typeOfIndex(inst); |
| ... | @@ -1153,7 +1208,7 @@ pub const DeclGen = struct { | ... | @@ -1153,7 +1208,7 @@ pub const DeclGen = struct { |
| 1153 | // Rather than generating into code here, we're just going to generate directly into the functions section so that | 1208 | // Rather than generating into code here, we're just going to generate directly into the functions section so that |
| 1154 | // variable declarations appear in the first block of the function. | 1209 | // variable declarations appear in the first block of the function. |
| 1155 | const storage_class = spirvStorageClass(ty.ptrAddressSpace()); | 1210 | const storage_class = spirvStorageClass(ty.ptrAddressSpace()); |
| 1156 | const section = if (storage_class == .Function) | 1211 | const section = if (storage_class == .Function or storage_class == .Generic) |
| 1157 | &self.func.prologue | 1212 | &self.func.prologue |
| 1158 | else | 1213 | else |
| 1159 | &self.spv.sections.types_globals_constants; | 1214 | &self.spv.sections.types_globals_constants; |
| ... | @@ -1321,6 +1376,27 @@ pub const DeclGen = struct { | ... | @@ -1321,6 +1376,27 @@ pub const DeclGen = struct { |
| 1321 | } | 1376 | } |
| 1322 | } | 1377 | } |
| 1323 | | 1378 | |
| | 1379 | fn airRetLoad(self: *DeclGen, inst: Air.Inst.Index) !void { |
| | 1380 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 1381 | const ptr_ty = self.air.typeOf(un_op); |
| | 1382 | const ret_ty = ptr_ty.childType(); |
| | 1383 | const ret_ty_id = try self.resolveTypeId(ret_ty); |
| | 1384 | |
| | 1385 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 1386 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| | 1387 | return; |
| | 1388 | } |
| | 1389 | |
| | 1390 | const ptr = try self.resolve(un_op); |
| | 1391 | const result_id = self.spv.allocId(); |
| | 1392 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| | 1393 | .id_result_type = ret_ty_id, |
| | 1394 | .id_result = result_id, |
| | 1395 | .pointer = ptr, |
| | 1396 | }); |
| | 1397 | try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = result_id.toRef() }); |
| | 1398 | } |
| | 1399 | |
| 1324 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { | 1400 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 1325 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1401 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1326 | const dst_ptr_id = try self.resolve(bin_op.lhs); | 1402 | const dst_ptr_id = try self.resolve(bin_op.lhs); |