| ... | ... | @@ -450,6 +450,42 @@ pub const DeclGen = struct { |
| 450 | 450 | return result_id; |
| 451 | 451 | } |
| 452 | 452 | |
| 453 | fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef { |
| 454 | const mod = self.module; |
| 455 | const ty_ref = try self.resolveType(ty, .direct); |
| 456 | const ty_id = self.typeId(ty_ref); |
| 457 | const decl = mod.declPtr(decl_index); |
| 458 | const spv_decl_index = try self.resolveDecl(decl_index); |
| 459 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { |
| 460 | .func => { |
| 461 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 462 | // just generate an empty pointer. Function pointers are represented by usize for now, |
| 463 | // though. |
| 464 | // TODO: Add dependency |
| 465 | return try self.spv.constInt(ty_ref, 0); |
| 466 | }, |
| 467 | .extern_func => unreachable, // TODO |
| 468 | else => { |
| 469 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 470 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| 471 | |
| 472 | switch (decl.@"addrspace") { |
| 473 | .generic => { |
| 474 | // Pointer should be generic, but is actually placed in CrossWorkgroup. |
| 475 | const result_id = self.spv.allocId(); |
| 476 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 477 | .id_result_type = ty_id, |
| 478 | .id_result = result_id, |
| 479 | .pointer = decl_id, |
| 480 | }); |
| 481 | return result_id; |
| 482 | }, |
| 483 | else => return decl_id, // Variable is already correct, probably. Maybe needs a bitcast? |
| 484 | } |
| 485 | }, |
| 486 | } |
| 487 | } |
| 488 | |
| 453 | 489 | const IndirectConstantLowering = struct { |
| 454 | 490 | const undef = 0xAA; |
| 455 | 491 | |
| ... | ... | @@ -1151,6 +1187,42 @@ pub const DeclGen = struct { |
| 1151 | 1187 | const int_ty = ty.intTagType(mod); |
| 1152 | 1188 | return try self.constant(int_ty, int_val, repr); |
| 1153 | 1189 | }, |
| 1190 | .ptr => |ptr| { |
| 1191 | const ptr_ty = switch (ptr.len) { |
| 1192 | .none => ty, |
| 1193 | else => ty.slicePtrFieldType(mod), |
| 1194 | }; |
| 1195 | const ptr_id = switch (ptr.addr) { |
| 1196 | .decl => |decl| try self.constructDeclRef(ptr_ty, decl), |
| 1197 | .mut_decl => |mut_decl| try self.constructDeclRef(ptr_ty, mut_decl.decl), // TODO |
| 1198 | .int => |int| blk: { |
| 1199 | const ptr_id = self.spv.allocId(); |
| 1200 | // TODO: This can probably be an OpSpecConstantOp Bitcast, but |
| 1201 | // that is not implemented by Mesa yet. Therefore, just generate it |
| 1202 | // as a runtime operation. |
| 1203 | try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ |
| 1204 | .id_result_type = try self.resolveTypeId(ptr_ty), |
| 1205 | .id_result = ptr_id, |
| 1206 | .integer_value = try self.constant(Type.usize, int.toValue(), .direct), |
| 1207 | }); |
| 1208 | break :blk ptr_id; |
| 1209 | }, |
| 1210 | .comptime_field => unreachable, |
| 1211 | else => |tag| return self.todo("pointer value of type {s}", .{@tagName(tag)}), |
| 1212 | }; |
| 1213 | if (ptr.len == .none) { |
| 1214 | return ptr_id; |
| 1215 | } |
| 1216 | |
| 1217 | const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); |
| 1218 | const result_id = self.spv.allocId(); |
| 1219 | try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ |
| 1220 | .id_result_type = self.typeId(result_ty_ref), |
| 1221 | .id_result = result_id, |
| 1222 | .constituents = &.{ ptr_id, len_id }, |
| 1223 | }); |
| 1224 | return result_id; |
| 1225 | }, |
| 1154 | 1226 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1155 | 1227 | // OpVariable that is not really required. |
| 1156 | 1228 | else => { |