| ... | @@ -452,7 +452,7 @@ pub const DeclGen = struct { | ... | @@ -452,7 +452,7 @@ pub const DeclGen = struct { |
| 452 | constituents[i] = self.spv.allocId(); | 452 | constituents[i] = self.spv.allocId(); |
| 453 | try self.genConstant(constituents[i], elem_ty, elem_val, repr); | 453 | try self.genConstant(constituents[i], elem_ty, elem_val, repr); |
| 454 | } | 454 | } |
| 455 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 455 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 456 | .id_result_type = result_ty_id, | 456 | .id_result_type = result_ty_id, |
| 457 | .id_result = result_id, | 457 | .id_result = result_id, |
| 458 | .constituents = constituents, | 458 | .constituents = constituents, |
| ... | @@ -474,7 +474,7 @@ pub const DeclGen = struct { | ... | @@ -474,7 +474,7 @@ pub const DeclGen = struct { |
| 474 | constituents[len] = self.spv.allocId(); | 474 | constituents[len] = self.spv.allocId(); |
| 475 | try self.genConstant(constituents[len], elem_ty, sentinel, repr); | 475 | try self.genConstant(constituents[len], elem_ty, sentinel, repr); |
| 476 | } | 476 | } |
| 477 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 477 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 478 | .id_result_type = result_ty_id, | 478 | .id_result_type = result_ty_id, |
| 479 | .id_result = result_id, | 479 | .id_result = result_id, |
| 480 | .constituents = constituents, | 480 | .constituents = constituents, |
| ... | @@ -494,7 +494,7 @@ pub const DeclGen = struct { | ... | @@ -494,7 +494,7 @@ pub const DeclGen = struct { |
| 494 | elem.* = self.spv.allocId(); | 494 | elem.* = self.spv.allocId(); |
| 495 | try self.genConstant(elem.*, elem_ty, elem_vals[i], repr); | 495 | try self.genConstant(elem.*, elem_ty, elem_vals[i], repr); |
| 496 | } | 496 | } |
| 497 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 497 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 498 | .id_result_type = result_ty_id, | 498 | .id_result_type = result_ty_id, |
| 499 | .id_result = result_id, | 499 | .id_result = result_id, |
| 500 | .constituents = elem_refs, | 500 | .constituents = elem_refs, |
| ... | @@ -547,7 +547,7 @@ pub const DeclGen = struct { | ... | @@ -547,7 +547,7 @@ pub const DeclGen = struct { |
| 547 | }; | 547 | }; |
| 548 | defer self.spv.gpa.free(constituents); | 548 | defer self.spv.gpa.free(constituents); |
| 549 | | 549 | |
| 550 | try section.emit(self.spv.gpa, .OpConstantComposite, .{ | 550 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| 551 | .id_result_type = result_ty_id, | 551 | .id_result_type = result_ty_id, |
| 552 | .id_result = result_id, | 552 | .id_result = result_id, |
| 553 | .constituents = constituents, | 553 | .constituents = constituents, |
| ... | @@ -558,11 +558,7 @@ pub const DeclGen = struct { | ... | @@ -558,11 +558,7 @@ pub const DeclGen = struct { |
| 558 | const decl_index = val.castTag(.decl_ref).?.data; | 558 | const decl_index = val.castTag(.decl_ref).?.data; |
| 559 | const decl_result_id = self.spv.allocId(); | 559 | const decl_result_id = self.spv.allocId(); |
| 560 | try self.genDeclRef(decl_result_id, decl_index); | 560 | try self.genDeclRef(decl_result_id, decl_index); |
| 561 | try section.emit(self.spv.gpa, .OpVariable, .{ | 561 | try self.variable(.global, result_id, result_ty_ref, decl_result_id); |
| 562 | .id_result_type = result_ty_id, | | |
| 563 | .id_result = result_id, | | |
| 564 | .storage_class = spirvStorageClass(ty.ptrAddressSpace()), | | |
| 565 | }); | | |
| 566 | }, | 562 | }, |
| 567 | else => return self.todo("constant pointer of value type {s}", .{@tagName(val.tag())}), | 563 | else => return self.todo("constant pointer of value type {s}", .{@tagName(val.tag())}), |
| 568 | }, | 564 | }, |
| ... | @@ -1490,48 +1486,73 @@ pub const DeclGen = struct { | ... | @@ -1490,48 +1486,73 @@ pub const DeclGen = struct { |
| 1490 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); | 1486 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); |
| 1491 | } | 1487 | } |
| 1492 | | 1488 | |
| 1493 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 1489 | fn variable( |
| 1494 | if (self.liveness.isUnused(inst)) return null; | 1490 | self: *DeclGen, |
| 1495 | const ty = self.air.typeOfIndex(inst); | 1491 | comptime context: enum { function, global }, |
| 1496 | const result_ty_ref = try self.resolveType(ty, .direct); | 1492 | result_id: IdRef, |
| 1497 | const result_ty_id = self.typeId(result_ty_ref); | 1493 | ptr_ty_ref: SpvType.Ref, |
| 1498 | const result_id = self.spv.allocId(); | 1494 | initializer: ?IdRef, |
| 1499 | | 1495 | ) !void { |
| 1500 | const storage_class = spirvStorageClass(ty.ptrAddressSpace()); | 1496 | const storage_class = self.spv.typeRefType(ptr_ty_ref).payload(.pointer).storage_class; |
| 1501 | | | |
| 1502 | const ptr_ty_id = switch (storage_class) { | | |
| 1503 | .Generic => blk: { | | |
| 1504 | const payload = try self.spv.arena.create(SpvType.Payload.Pointer); | | |
| 1505 | payload.* = self.spv.typeRefType(result_ty_ref).payload(.pointer).*; | | |
| 1506 | payload.storage_class = .Function; | | |
| 1507 | break :blk try self.spv.resolveTypeId(SpvType.initPayload(&payload.base)); | | |
| 1508 | }, | | |
| 1509 | else => result_ty_id, | | |
| 1510 | }; | | |
| 1511 | const actual_storage_class = switch (storage_class) { | 1497 | const actual_storage_class = switch (storage_class) { |
| 1512 | .Generic, .Function => .Function, | 1498 | .Generic => switch (context) { |
| | 1499 | .function => .Function, |
| | 1500 | .global => .CrossWorkgroup, |
| | 1501 | }, |
| 1513 | else => storage_class, | 1502 | else => storage_class, |
| 1514 | }; | 1503 | }; |
| 1515 | const section = switch (storage_class) { | 1504 | const actual_ptr_ty_ref = switch (storage_class) { |
| | 1505 | .Generic => try self.spv.changePtrStorageClass(ptr_ty_ref, actual_storage_class), |
| | 1506 | else => ptr_ty_ref, |
| | 1507 | }; |
| | 1508 | const alloc_result_id = switch (storage_class) { |
| | 1509 | .Generic => self.spv.allocId(), |
| | 1510 | else => result_id, |
| | 1511 | }; |
| | 1512 | |
| | 1513 | const section = switch (actual_storage_class) { |
| | 1514 | .Generic => unreachable, |
| 1516 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to | 1515 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to |
| 1517 | // directly generate them into func.prologue instead of the body. | 1516 | // directly generate them into func.prologue instead of the body. |
| 1518 | .Generic, .Function => &self.func.prologue, | 1517 | .Function => &self.func.prologue, |
| 1519 | else => &self.spv.sections.types_globals_constants, | 1518 | else => &self.spv.sections.types_globals_constants, |
| 1520 | }; | 1519 | }; |
| 1521 | try section.emit(self.spv.gpa, .OpVariable, .{ | 1520 | try section.emit(self.spv.gpa, .OpVariable, .{ |
| 1522 | .id_result_type = ptr_ty_id, | 1521 | .id_result_type = self.typeId(actual_ptr_ty_ref), |
| 1523 | .id_result = result_id, | 1522 | .id_result = alloc_result_id, |
| 1524 | .storage_class = actual_storage_class, | 1523 | .storage_class = actual_storage_class, |
| | 1524 | .initializer = initializer, |
| 1525 | }); | 1525 | }); |
| 1526 | if (storage_class == .Generic) { | 1526 | |
| 1527 | const casted_result_id = self.spv.allocId(); | 1527 | if (storage_class != .Generic) { |
| 1528 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | 1528 | return; |
| 1529 | .id_result_type = result_ty_id, | 1529 | } |
| 1530 | .id_result = casted_result_id, | 1530 | |
| 1531 | .pointer = result_id, | 1531 | // Now we need to convert the pointer. |
| 1532 | }); | 1532 | // If this is a function local, we need to perform the conversion at runtime. Otherwise, we can do |
| 1533 | return casted_result_id; | 1533 | // it ahead of time using OpSpecConstantOp. |
| | 1534 | switch (actual_storage_class) { |
| | 1535 | .Function => try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| | 1536 | .id_result_type = self.typeId(ptr_ty_ref), |
| | 1537 | .id_result = result_id, |
| | 1538 | .pointer = alloc_result_id, |
| | 1539 | }), |
| | 1540 | else => { |
| | 1541 | try section.emitRaw(self.spv.gpa, .OpSpecConstantOp, 3 + 1); |
| | 1542 | section.writeOperand(IdRef, self.typeId(ptr_ty_ref)); |
| | 1543 | section.writeOperand(IdRef, result_id); |
| | 1544 | section.writeOperand(Opcode, .OpPtrCastToGeneric); |
| | 1545 | section.writeOperand(IdRef, alloc_result_id); |
| | 1546 | }, |
| 1534 | } | 1547 | } |
| | 1548 | } |
| | 1549 | |
| | 1550 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| | 1551 | if (self.liveness.isUnused(inst)) return null; |
| | 1552 | const ty = self.air.typeOfIndex(inst); |
| | 1553 | const result_ty_ref = try self.resolveType(ty, .direct); |
| | 1554 | const result_id = self.spv.allocId(); |
| | 1555 | try self.variable(.function, result_id, result_ty_ref, null); |
| 1535 | return result_id; | 1556 | return result_id; |
| 1536 | } | 1557 | } |
| 1537 | | 1558 | |