authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-11-27 01:17:38+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-09 01:51:49+02:00
logbca6f2901af5e2ff30f1ff1780eb23b5e05e2f86
tree873d727c4a0a3d23e187010bf7a72c3eae73b0b8
parent6146abee1ef19f1c5380d0afba6f38895ce81e0b
signaturelock-open Commit is signed but in an unrecognized format.

spirv: enum values, struct_field_val, ret_ptr, ret_load

Implements lowering for enum constants, as well as the struct_field_val, ret_ptr, and ret_load AIR instructions.

1 files changed, 86 insertions(+), 10 deletions(-)

src/codegen/spirv.zig+86-10
...@@ -429,9 +429,33 @@ pub const DeclGen = struct {...@@ -429,9 +429,33 @@ pub const DeclGen = struct {
429 },429 },
430 else => unreachable, // TODO430 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 }
436460
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),
744768
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),
751777
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),
756784
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(),
766795
...@@ -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 }
11461175
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 that1208 // 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.prologue1212 &self.func.prologue
1158 else1213 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 }
13231378
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);